package com.bestcem.xm.deliver.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bestcem.xm.common.core.constant.AppResourceErrorCode;
import com.bestcem.xm.common.core.constant.ReqErrorCodeConstants;
import com.bestcem.xm.common.core.constant.ResourceErrorCodeConstants;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.enums.ReqErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum;
import com.bestcem.xm.common.core.enums.ValidationErrorCodeEnum;
import com.bestcem.xm.common.core.exception.BusinessException;
import com.bestcem.xm.common.core.oss.enums.OssPathEnum;
import com.bestcem.xm.common.core.uitls.DynamicEasyExcelImportUtil;
import com.bestcem.xm.common.core.uitls.EmailUtil;
import com.bestcem.xm.common.core.uitls.SignUtil;
import com.bestcem.xm.component.mybatis.service.impl.XmServiceImpl;
import com.bestcem.xm.component.security.context.SecurityContextHolder;
import com.bestcem.xm.componet.filestorage.service.StorageService;
import com.bestcem.xm.deliver.controller.param.EmailRecordsPageParam;
import com.bestcem.xm.deliver.controller.v2.param.EmailDeliversParam;
import com.bestcem.xm.deliver.controller.v2.param.EmailDeliversParamAgain;
import com.bestcem.xm.deliver.controller.v2.param.MemberDeliverDataByEmail;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverEmailRecordVo;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverGroupListVo;
import com.bestcem.xm.deliver.controller.v2.vo.DeliverGroupVo;
import com.bestcem.xm.deliver.convert.DeliverConvertMapper;
import com.bestcem.xm.deliver.entity.*;
import com.bestcem.xm.deliver.enums.*;
import com.bestcem.xm.deliver.grpc.client.MemberGrpcClient;
import com.bestcem.xm.deliver.grpc.client.QdesGrpcClient;
import com.bestcem.xm.deliver.grpc.client.SurveyGrpcClient;
import com.bestcem.xm.deliver.grpc.client.UserGrpcClient;
import com.bestcem.xm.deliver.grpc.client.dto.MemberDto;
import com.bestcem.xm.deliver.grpc.client.dto.OrgInfoDto;
import com.bestcem.xm.deliver.grpc.v1.services.*;
import com.bestcem.xm.deliver.mapper.*;
import com.bestcem.xm.deliver.mq.dto.EmailDeliverMessageDto;
import com.bestcem.xm.deliver.mq.send.biz.DeliverMessageSendService;
import com.bestcem.xm.deliver.service.DeliverDeliverService;
import com.bestcem.xm.deliver.service.DeliverEmailDeliverService;
import com.bestcem.xm.deliver.service.ServiceSequenceService;
import com.bestcem.xm.qdes.grpc.v1.services.Project;
import com.bestcem.xm.qdes.grpc.v1.services.QStruct;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.bson.types.ObjectId;
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
import org.springframework.retry.policy.SimpleRetryPolicy;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.bestcem.xm.common.core.enums.ResourceErrorCodeEnum.STATUS_CHANGED;
import static com.bestcem.xm.common.core.uitls.CommonUtil.URL_REGEX;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_START;
import static com.bestcem.xm.deliver.enums.DeliverStatusEnum.DELIVER_STATUS_STOP;
import static com.bestcem.xm.deliver.enums.DeliverSurveyDataSurveyStatusEnum.DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER;
import static com.bestcem.xm.deliver.enums.DeliverTtypeEnum.DELIVER_TTYPE_EMAIL;
import static com.bestcem.xm.deliver.enums.DeliverTtypeEnum.DELIVER_TTYPE_SMS;
import static com.bestcem.xm.deliver.enums.EmailRecordStatusEnum.*;
import static com.bestcem.xm.deliver.enums.RespondentStatusEnum.RESPONDENT_STATUS_FINISH;
import static com.bestcem.xm.deliver.enums.RespondentStatusEnum.RESPONDENT_STATUS_NOTSTART;
import static com.bestcem.xm.deliver.enums.SurverySubmitTyeEnum.LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE;
import static com.bestcem.xm.deliver.enums.SurverySubmitTyeEnum.LIMITED_ONE_SURVERY_SUBMINT_TYPE;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverAwardUseType.DELIVER_AWARD_USE_TYPE_UNUSE;
import static com.bestcem.xm.deliver.grpc.v1.services.DeliverAwardUseType.DELIVER_AWARD_USE_TYPE_USE;
import static com.bestcem.xm.deliver.grpc.v1.services.EmailRecordSType.EMAILRECORD_S_TYPE_DELIVER;
import static com.bestcem.xm.deliver.grpc.v1.services.EmailRecordSType.EMAILRECORD_S_TYPE_URGE;
import static com.bestcem.xm.deliver.grpc.v1.services.SMSRecordSType.SMSRECORD_S_TYPE_URGE;
import static com.bestcem.xm.deliver.util.DeliverConstant.DELIVER_MQ_BATCH_SIZE;

/**
 * @author been
 * @description 针对表【ds_deliver_emaildeliver】的数据库操作Service实现
 * @createDate 2022-11-07 13:49:46
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DeliverEmailDeliverServiceImpl extends XmServiceImpl<DeliverEmailDeliverMapper, DeliverEmailDeliver> implements DeliverEmailDeliverService {
    private @NonNull DeliverConvertMapper deliverConvertMapper;
    private @NonNull DeliverDeliverGroupMapper deliverDeliverGroupMapper;
    private @NonNull DeliverDeliverSurveyDataMapper deliverDeliverSurveyDataMapper;
    private @NonNull DeliverEmailRecordMapper deliverEmailRecordMapper;
    private @NonNull DeliverDeliverMapper deliverDeliverMapper;
    private @NonNull DeliverDeliverGroupDeliverMapper deliverDeliverGroupDeliverMapper;
    private @NonNull DeliverDeliverSurveyDataMapper deliverSurveyDataMapper;
    private @NonNull DeliverRecastMapper deliverRecastMapper;
    private @NonNull DeliverSurveyDeliverMapper deliverSurveyDeliverMapper;
    private @NonNull DeliverEmailDeliverMemberIdMapper deliverEmailDeliverMemberIdMapper;
    private @NonNull DeliverSmsDeliverMapper smsDeliverMapper;
    private @NonNull DeliverSmsRecordMapper deliverSmsRecordMapper;

    private @NonNull MemberGrpcClient memberGrpcClient;
    private @NonNull SurveyGrpcClient surveyGrpcClient;
    private @NonNull UserGrpcClient userGrpcClient;
    private @NonNull QdesGrpcClient qdesGrpcClient;

    //private @NonNull DeliverSmsDeliverService deliverSmsDeliverService;
    private @NonNull DeliverDeliverService deliverService;
    private @NonNull DeliverMessageSendService deliverMessageSendService;
    //private @NonNull DeliverDeliverTriggerService deliverDeliverTriggerService;
    private @NonNull ServiceSequenceService serviceSequenceService;
    private @NonNull StorageService storageService;

    private static final String SEPARATOR = "/";
    public static final String EMAILDELIVER_EXPORT = "emaildeliver/export/";

    /**
     * 短信内容<p></p>标签正则匹配
     */
    public static final Pattern P_PATTERN = Pattern.compile("(<p.*?>)|(</p>)");

    /**
     * 邮件内容<p></p>标签正则匹配
     */
    public static final Pattern P_PATTERN_EMAIL = Pattern.compile("\\$\\{问卷链接=\"(.+?)\"}");

    @Override
    public List<DeliverGroupListVo> qdesDeliverGroup(String surveyId) {
        List<DeliverGroupListVo> deliverGroupList = deliverDeliverGroupMapper.getDeliverGroupList(SecurityContextHolder.getOrgId(), surveyId);
        log.info("获取到的当前问卷：{}的投放组有{}个", surveyId, deliverGroupList.size());
        int index = 1;
        for (DeliverGroupListVo v : deliverGroupList) {
            v.setDeliverGName("投放组" + index);
            index++;
        }
        return deliverGroupList;
    }

    @Override
    public ServiceResult<?> emailDeliverRecord(Page<DeliverEmailRecord> page, EmailRecordsPageParam param) {
        String projectId = param.getProjectId();
        String emailDeliverId = param.getEmailDeliverId();
        DeliverEmailDeliver emailDeliver = originGetEmailDeliver(emailDeliverId);
        String status = param.getStatus();
        String search = param.getSearch();
        Boolean urged = Objects.nonNull(param.getUrged()) ? Boolean.valueOf(param.getUrged()) : null;
        String deliverGroupId = emailDeliver.getDeliverGroupId();
        String deliverId = emailDeliver.getDeliverId();
        Map<String, List<Integer>> memberMap = getDeliverDataMember(urged, param.getSurveyStatus(), deliverGroupId, deliverId, null);
        Set<String> memberSurveydataIds = memberMap.keySet();
        Integer checkSubmit = emailDeliver.getCheckSubmit();
        String surveyRespStatus = param.getSurveyRespStatus();
        List<String> memberIds = Objects.equals(urged, true) ? new ArrayList<>(memberSurveydataIds) : deliverService.getDeliverMemberIdList(deliverId, DELIVER_TTYPE_EMAIL);
        Map<String, Integer> memberRespMaps = new HashMap<>();
        deliverService.getMemberRespMaps(projectId, surveyRespStatus, deliverId, checkSubmit, memberRespMaps, memberIds);

        Set<String> memberRespIds = memberRespMaps.keySet();

        LambdaQueryWrapper<DeliverEmailRecord> queryWrapper = new LambdaQueryWrapper<>();
        commonWrapper(queryWrapper, status, emailDeliverId, search);
        //只查询去重的member_id
        queryWrapper.select(DeliverEmailRecord::getMemberId);
        if (Objects.nonNull(urged) || Objects.nonNull(surveyRespStatus)) {
            memberIds = new ArrayList<>(CollectionUtils.intersection(memberSurveydataIds, new HashSet<>(memberRespIds)));
            if (memberIds.isEmpty()) {
                return ServiceResult.success(Collections.emptyList());
            }
            queryWrapper.in(DeliverEmailRecord::getMemberId, memberIds);
        }
        queryWrapper.eq(DeliverEmailRecord::getSType, EMAILRECORD_S_TYPE_DELIVER.getNumber());
        queryWrapper.orderByDesc(DeliverEmailRecord::getMemberId);
        page = deliverEmailRecordMapper.selectPage(page, queryWrapper);
        List<DeliverEmailRecord> records = page.getRecords();
        if (records.isEmpty()) {
            return ServiceResult.success(Collections.emptyList());
        }
        List<Map<String, Object>> emailRecordData = new ArrayList<>(records.size());
        queryWrapper.clear();
        commonWrapper(queryWrapper, status, emailDeliverId, search);
        for (DeliverEmailRecord record : records) {
            queryWrapper.eq(DeliverEmailRecord::getMemberId, record.getMemberId());
            queryWrapper.orderByDesc(DeliverEmailRecord::getId);
            queryWrapper.last("limit 1");
            //每次投放，同一个联系人（MemberId）只会出现一次
            DeliverEmailRecord deliverEmailRecords = deliverEmailRecordMapper.selectOne(queryWrapper);
            Map<String, Object> mp = new HashMap<>(4);
            mp.put("id", "member_id");
            mp.put("ret", deliverEmailRecords);
            emailRecordData.add(mp);
        }
        boolean displayContact;
        if (CollectionUtils.isNotEmpty(memberIds) && StringUtils.isEmpty(param.getDisplayContact())) {
            displayContact = memberGrpcClient.checkDisplayRangePermission(SecurityContextHolder.getOrgId(), SecurityContextHolder.getUserId(), memberIds.get(0));
        } else {
            displayContact = false;
        }
        List<DeliverEmailRecordVo> rets = emailRecordData.stream().map(item -> setItem(item, checkSubmit, memberMap, memberRespMaps, displayContact)).collect(Collectors.toList());
        return ServiceResult.success(rets);
    }

    private DeliverEmailRecordVo setItem(Map<String, Object> item, Integer checkSubmit, Map<String, List<Integer>> memberMap, Map<String, Integer> memberRespMaps, boolean displayContact) {
        DeliverEmailRecord old = JSONObject.parseObject(JSON.toJSONString(item.get("ret")), DeliverEmailRecord.class);
        DeliverEmailRecordVo vo = deliverConvertMapper.emailRecord2Vo(old);
        String memberId = old.getMemberId();
        int urge_n, survey_n, survey_s;
        if (memberMap.containsKey(memberId)) {
            List<Integer> list = memberMap.get(memberId);
            urge_n = list.stream().findFirst().orElse(0);
            survey_n = list.get(1);
            survey_s = list.get(2);
        } else {
            urge_n = 0;
            survey_n = 0;
            survey_s = DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER.getValue();
        }
        vo.setUrgeNums(urge_n);
        vo.setSurveyNums(survey_n);
        vo.setSurveyRespStatus(survey_s);
        if (checkSubmit == 0) {
            vo.setFinished(memberRespMaps.getOrDefault(memberId, 0));
        } else {
            vo.setSurveyRespStatus(memberRespMaps.getOrDefault(memberId, RESPONDENT_STATUS_NOTSTART.getValue()));
        }
        if (!displayContact && StringUtils.isNotEmpty(vo.getEmail())) {
            vo.setEmail(hideEmail(vo.getEmail(), true));
        }
        return vo;
    }

    /**
     * 隐藏邮箱中间几位
     *
     * @param email
     * @param noThrow true：不抛出异常
     * @return
     */
    private String hideEmail(String email, boolean noThrow) {
        if (!EmailUtil.validateEmail(email)) {
            if (noThrow) {
                return "";
            }
            throw new BusinessException(String.valueOf(ValidationErrorCodeEnum.EMAIL_ERROR.getCode()), String.format("email error: {%s}", email));
        }
        return String.format("****@%s", email.split("@")[1]);
    }

    private void commonWrapper(LambdaQueryWrapper<DeliverEmailRecord> queryWrapper, String status, String emailDeliverId, String search) {
        queryWrapper.eq(DeliverEmailRecord::getEmailDeliverId, emailDeliverId);
        queryWrapper.eq(StringUtils.isNotEmpty(status), DeliverEmailRecord::getStatus, status);
        queryWrapper.and(StringUtils.isNotEmpty(search), wrapper -> wrapper.like(DeliverEmailRecord::getUsername, search).or().like(DeliverEmailRecord::getEmail, search));
    }

    private DeliverEmailDeliver originGetEmailDeliver(String emailDeliverId) {
        DeliverEmailDeliver emailDeliver = baseMapper.selectById(emailDeliverId);
        if (Objects.isNull(emailDeliver)) {
            throw new BusinessException(String.valueOf(AppResourceErrorCode.NOT_FOUND), String.format("EmailDeliver[id=%s] not found", emailDeliverId));
        }
        return emailDeliver;
    }

    @Override
    public Map<String, List<Integer>> getDeliverDataMember(Boolean urged, String surveyStatus, String deliverGroupId, String deliverId, List<String> member_ids) {
        LambdaQueryWrapper<DeliverDeliverSurveyData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(CollectionUtils.isNotEmpty(member_ids), DeliverDeliverSurveyData::getMemberId, member_ids);
        queryWrapper.eq(NumberUtils.isDigits(surveyStatus), DeliverDeliverSurveyData::getSurveyStatus, surveyStatus);
        if (StrUtil.isNotEmpty(deliverGroupId)) {
            queryWrapper.eq(DeliverDeliverSurveyData::getDeliverGroupId, deliverGroupId);
        } else {
            queryWrapper.eq(DeliverDeliverSurveyData::getDeliverId, deliverId);
        }
        if (Objects.nonNull(urged)) {
            queryWrapper.gt(urged, DeliverDeliverSurveyData::getUrgeNums, 0);
            queryWrapper.eq(!urged, DeliverDeliverSurveyData::getUrgeNums, 0);
        }
        List<DeliverDeliverSurveyData> deliverDeliverSurveyData = deliverDeliverSurveyDataMapper.selectList(queryWrapper);
        return deliverDeliverSurveyData.stream().collect(Collectors.toMap(DeliverDeliverSurveyData::getMemberId, v -> Arrays.asList(v.getUrgeNums(), v.getSurveyNums(), v.getSurveyStatus()), (a, b) -> a));
    }

    @Override
    public DeliverDeliver getDeliver(String deliverId) {
        DeliverDeliver deliver = deliverDeliverMapper.selectById(deliverId);
        if (Objects.isNull(deliver)) {
            throw new BusinessException(AppResourceErrorCode.NOT_FOUND.toString(), String.format("SMSDeliver[id=%s] not found", deliverId));
        }
        return deliver;
    }

    private DeliverEmailDeliver getEmailDeliverByDeliver(String deliverId) {
        LambdaQueryWrapper<DeliverEmailDeliver> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverEmailDeliver::getDeliverId, deliverId);
        DeliverEmailDeliver emailDeliver = baseMapper.selectOne(queryWrapper);
        if (Objects.isNull(emailDeliver)) {
            throw new BusinessException(AppResourceErrorCode.NOT_FOUND.toString(), String.format("EmailDeliver[id=%s] not found", deliverId));
        }
        return emailDeliver;
    }

    @Override
    public ServiceResult<?> urgeRecord(String deliverId, String memberId, String deliverGroupId) {
        DeliverDeliver deliver = getDeliver(deliverId);
        Integer ttype = deliver.getTtype();
        if (ttype == DELIVER_TTYPE_SMS.getValue()) {
            LambdaQueryWrapper<DeliverSmsDeliver> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeliverSmsDeliver::getDeliverId, deliverId);
            DeliverSmsDeliver smsDeliver = smsDeliverMapper.selectOne(queryWrapper);
            if (Objects.isNull(smsDeliver)) {
                return ServiceResult.fail(String.format("SMSDeliver[id=%s] not found", deliverId));
            }
            deliverGroupId = smsDeliver.getDeliverGroupId();
        } else if (ttype == DELIVER_TTYPE_EMAIL.getValue()) {
            deliverGroupId = getEmailDeliverByDeliver(deliverId).getDeliverGroupId();
        }
        return getMemberUrgeRecord(memberId, deliverGroupId, deliverId);
    }

    @Override
    public void triggerDeliverStatus(DeliverDeliver deliver, String action) {
        DeliverEmailDeliver email_deliver = Optional.ofNullable(baseMapper.selectOne(new QueryWrapper<DeliverEmailDeliver>().lambda().eq(DeliverEmailDeliver::getDeliverId, deliver.getId()))).orElseThrow(() -> new BusinessException(String.format("DeliverEmailDeliver[deliverId=%s] not found", deliver.getId())));
        JSONObject param = new JSONObject();
        param.put("version", deliver.getVersion());

        if (StrUtil.equals("done", action) && email_deliver.getIsDelay().equals(0)) {
            deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_START.getValue()));
            //立即投放
            beforeDeliverEmailDeliver(email_deliver, param, deliver, true, null);
        } else if (StrUtil.equals("done", action) && email_deliver.getIsDelay().equals(1)) {
            //延迟投放
            if (LocalDateTime.now().isAfter(email_deliver.getDeliverTime())) {
                //如果已经错过定时投放的投放时间，则状态为 未投放
                deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_STOP.getValue()));
                throw new BusinessException("投放时间过期");
            }

            Date delayDate = Date.from(email_deliver.getDeliverTime().atZone(ZoneId.systemDefault()).toInstant());
            beforeDeliverEmailDeliver(email_deliver, param, deliver, true, delayDate);
        } else if (StrUtil.equals("review_success", action) && email_deliver.getIsDelay().equals(1)) {
            //延迟投放
            if (LocalDateTime.now().isAfter(email_deliver.getDeliverTime())) {
                //如果已经错过定时投放的投放时间，则状态为 未投放
                deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_STOP.getValue()));
                throw new BusinessException("投放时间过期");
            }

            Date delayDate = Date.from(email_deliver.getDeliverTime().atZone(ZoneId.systemDefault()).toInstant());
            beforeDeliverEmailDeliver(email_deliver, param, deliver, true, delayDate);
        } else if (StrUtil.equals("review_success", action) && email_deliver.getIsDelay().equals(0)) {
            boolean check_delay_result = deliverService.inCheckDelay(JSONArray.parseArray(email_deliver.getAntiDisturTimes()));
            if (check_delay_result) {
                JSONObject option_deliver_time = JSON.parseObject(email_deliver.getOptionDeliverTime());
                if (!option_deliver_time.isEmpty()) {
                    String hour = option_deliver_time.getString("hour");
                    String minute = option_deliver_time.getString("minute");
                    LocalDate date = LocalDate.now().plusDays(1);
                    LocalTime time = LocalTime.of(Integer.parseInt(hour), Integer.parseInt(minute));
                    LocalDateTime deliver_time = LocalDateTime.of(date, time);
                    Date delayDate = Date.from(deliver_time.atZone(ZoneId.systemDefault()).toInstant());
                    beforeDeliverEmailDeliver(email_deliver, param, deliver, true, delayDate);
                } else {
                    deliverDeliverMapper.update(null, new UpdateWrapper<DeliverDeliver>().lambda().eq(DeliverDeliver::getId, deliver.getId()).set(DeliverDeliver::getStatus, DELIVER_STATUS_STOP.getValue()));
                }
            } else {
                //立即投放
                beforeDeliverEmailDeliver(email_deliver, param, deliver, true, null);
            }
        }
    }

    /**
     * 根据投放组id/投放id 获取催答记录
     *
     * @param memberId
     * @param deliverGroupId
     * @param deliverId
     */
    private ServiceResult<?> getMemberUrgeRecord(String memberId, String deliverGroupId, String deliverId) {
        List<Map<String, Object>> retList = new ArrayList<>();
        List<DeliverDeliver> deliverDeliversList;
        if (StringUtils.isNotEmpty(deliverGroupId)) {
            //投放组的催答记录
            originGetDeliverGroup(deliverGroupId);
            DeliverGroupVo deliverDeliverGroup = deliverDeliverGroupMapper.getDeliverGroup(deliverGroupId);
            List<DeliverDeliverGroupDeliver> deliverList = deliverDeliverGroup.getDeliverList();
            deliverDeliversList = CollUtil.isNotEmpty(deliverList)
                    ? deliverDeliverMapper.selectBatchIds(deliverList.stream().map(DeliverDeliverGroupDeliver::getDeliverId).collect(Collectors.toList()))
                    : Collections.emptyList();
        } else {
            //投放的催答记录
            deliverDeliversList = Collections.singletonList(getDeliver(deliverId));
        }
        List<String> smsDeliverList = new ArrayList<>();
        List<String> emailDeliverList = new ArrayList<>();
        deliverDeliversList.forEach(v -> {
            Integer ttype = v.getTtype();
            if (ttype == DELIVER_TTYPE_SMS.getValue()) {
                LambdaQueryWrapper<DeliverSmsDeliver> queryWrapper = new LambdaQueryWrapper<>();
                if (StrUtil.isNotEmpty(deliverGroupId)) {
                    queryWrapper.eq(DeliverSmsDeliver::getDeliverGroupId, deliverGroupId);
                } else {
                    queryWrapper.eq(DeliverSmsDeliver::getDeliverId, deliverId);
                }
                smsDeliverList.addAll(smsDeliverMapper.selectList(queryWrapper).stream().map(DeliverSmsDeliver::getId).collect(Collectors.toList()));
            } else if (ttype == DELIVER_TTYPE_EMAIL.getValue()) {
                emailDeliverList.addAll(originGetEmailDeliverList(deliverGroupId, deliverId).stream().map(DeliverEmailDeliver::getId).collect(Collectors.toList()));
            }
        });
        log.info("sms_deliver=={}, email_deliver_list={}", smsDeliverList, emailDeliverList);
        if (CollectionUtils.isNotEmpty(smsDeliverList)) {
            LambdaQueryWrapper<DeliverSmsRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeliverSmsRecord::getMemberId, memberId);
            queryWrapper.in(DeliverSmsRecord::getSmsDeliverId, smsDeliverList);
            queryWrapper.eq(DeliverSmsRecord::getSType, SMSRECORD_S_TYPE_URGE.getNumber());
            queryWrapper.orderByAsc(DeliverSmsRecord::getCreatedDt);
            queryWrapper.orderByDesc(DeliverSmsRecord::getUpdatedDt);

            List<DeliverSmsRecord> smsRecordList = deliverSmsRecordMapper.selectList(queryWrapper);
            smsRecordList.forEach(v -> {
                Map<String, Object> data = new HashMap<>();
                data.put("urge_time", v.getCreatedDt());
                data.put("status", v.getStatus());
                retList.add(data);
            });
        }
        if (CollectionUtils.isNotEmpty(emailDeliverList)) {
            List<DeliverEmailRecord> emailRecordList = getEmailRecordList(memberId, emailDeliverList);
            emailRecordList.forEach(v -> {
                Map<String, Object> data = new HashMap<>();
                data.put("urge_time", v.getCreatedDt());
                data.put("status", v.getStatus());
                retList.add(data);
            });
        }
        return ServiceResult.success(retList);
    }

    private List<DeliverEmailRecord> getEmailRecordList(String memberId, List<String> emailDeliverList) {
        LambdaQueryWrapper<DeliverEmailRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverEmailRecord::getMemberId, memberId);
        queryWrapper.in(DeliverEmailRecord::getEmailDeliverId, emailDeliverList);
        queryWrapper.eq(DeliverEmailRecord::getSType, EMAILRECORD_S_TYPE_URGE.getNumber());
        queryWrapper.orderByAsc(DeliverEmailRecord::getCreatedDt);
        queryWrapper.orderByDesc(DeliverEmailRecord::getUpdatedDt);
        return deliverEmailRecordMapper.selectList(queryWrapper);
    }

    public List<DeliverEmailDeliver> originGetEmailDeliverList(String deliverGroupId, String deliverId) {
        LambdaQueryWrapper<DeliverEmailDeliver> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(deliverGroupId)) {
            queryWrapper.eq(DeliverEmailDeliver::getDeliverGroupId, deliverGroupId);
        } else {
            queryWrapper.eq(DeliverEmailDeliver::getDeliverId, deliverId);
        }
        return baseMapper.selectList(queryWrapper);
    }

    @Override
    public ServiceResult<?> updateEmailDelivers(String id, JSONObject param) {
        DeliverEmailDeliver emailDeliver = baseMapper.selectById(id);
        if (Objects.isNull(emailDeliver)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, String.format("EmailDeliver[id=%s] not found", id));
        }
        String smtpId = param.getString("smtp_id");
        if (StringUtils.isEmpty(smtpId)) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "发件邮箱不能为空");
        }
        if (Objects.isNull(userGrpcClient.getUserSmtpById(smtpId))) {
            return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "发件邮箱Not Found");
        }
        String emailTemplate = param.getString("email_template");
        if (StringUtils.isNotEmpty(emailTemplate)) {
            if (!emailTemplate.contains("${问卷链接")) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_LOST, "邮件内容中未插入问卷链接");
            }
            if (emailTemplate.contains("${问卷链接=")) {
                //将邮件内容里的 {问卷链接="http://cloud-dev.bestcem.cn/contact/main"}替换为{问卷链接="http://clo"}，即问卷链接只取前十位（短链）
                Matcher matcher = P_PATTERN_EMAIL.matcher(emailTemplate);
                while (matcher.find()) {
                    String v = matcher.group();
                    String linkContent = v.substring(v.indexOf("\"") + 1, v.lastIndexOf("\""));
                    if (linkContent.length() > 10) {
                        emailTemplate.replace(linkContent, linkContent.substring(0, 10));
                    }
                }
            }
            Map<String, String> data = new HashMap(2);
            data.put("id", (String) updateEmailDeliver(emailDeliver, param).getData());
            return ServiceResult.success(data);
        }
        return ServiceResult.success();
    }


    private ServiceResult<?> updateEmailDeliver(DeliverEmailDeliver emailDeliver, JSONObject param) {
        JSONObject deliver_params = new JSONObject();
        param.forEach((key, value) -> {
            if (key.startsWith("_deliver_")) {
                String real_key = StrUtil.removePrefix(key, "_deliver_");
                deliver_params.put(real_key, value);
            }
        });
        if (!deliver_params.isEmpty()) {
            //解决定时任务，多次更新触发多个定时任务的问题, 时间戳取到微秒
            long version = System.currentTimeMillis() * 1000;
            deliver_params.put("version", version);
            DeliverDeliver updateDeliver = JSON.toJavaObject(deliver_params, DeliverDeliver.class);
            updateDeliver.setId(emailDeliver.getDeliverId());
            deliverDeliverMapper.updateById(updateDeliver);
        }

        //更新投放设置（部分） 和 更新联系人都会调用这个函数 判断filter_params 以确定是不是需要更新投放联系人列表的put
        List<String> not_distrub_member_list = new ArrayList<>();
        if (CollUtil.isNotEmpty(param.getJSONObject("filter_params"))) {
            if (param.containsKey("not_distrub_member")) {
                JSONArray notDistrubMembers = param.getJSONArray("not_distrub_member");
                log.info("邮件投放获取到的免打扰联系人列表----->>>>>{}", notDistrubMembers);
                if (!notDistrubMembers.isEmpty()) {
                    not_distrub_member_list = notDistrubMembers.stream().map(String::valueOf).collect(Collectors.toList());
                    param.put("no_disturb_member_id_list", not_distrub_member_list);
                }
            }
            Boolean isUpload = (Boolean) param.get("is_upload");
            if (Objects.isNull(isUpload) || !isUpload) {
                //提前过滤掉 免打扰的id列表，为了在编辑投放时，显示投放联系人时分页查询
                JSONObject filter_params = new JSONObject();
                //加入免打扰联系人ids
                filter_params.putAll(param.getJSONObject("filter_params"));
                filter_params.put("not_distrub_member", not_distrub_member_list);
                //增加过滤黑名单、邮件退订的联系人
                Map<String, Object> filter = new HashMap<>();
                filter.put("member_delivery_status", 1);
                filter.put("subscribe_status", 1);
                filter_params.put("filter", filter);
                filter_params.put("push_type", "email");

                Integer superRole = SecurityContextHolder.getToken().getSuperRole();
                Integer isSenior = SecurityContextHolder.getToken().getIsSenior();
                Map<String, Object> kwargs = new HashMap<>(8);
                kwargs.put("org_id", SecurityContextHolder.getOrgId());
                kwargs.put("user_id", SecurityContextHolder.getUserId());
                kwargs.put("super_admin", superRole == 1);
                kwargs.put("senior_admin", isSenior == 1);
                List<String> member_ids = memberGrpcClient.listMembersByFilterParam(kwargs, filter_params.toJSONString());
                param.put("member_id_list", member_ids);
            }
        }
        Map<String, Object> signMap = new HashMap<>(4);
        signMap.put("email_subject", Optional.ofNullable(param.getString("email_subject")).orElse(emailDeliver.getEmailSubject()));
        signMap.put("email_template", Optional.ofNullable(param.getString("email_template")).orElse(emailDeliver.getEmailTemplate()));
        String hashcode = SignUtil.genSign(signMap, deliverService.getDeliverSecret());
        param.put("hashcode", hashcode);
        originUpdateEmailDeliver(emailDeliver, param);

        if (param.containsKey("_sign") && param.getBooleanValue("_sign")) {
            // 这里会不会有一级缓存？查到的不是最新？
            emailDeliver = baseMapper.selectById(emailDeliver.getId());
            // 批量发送, 批量创建record
            return beforeDeliverEmailDeliver(emailDeliver, param, null, null, null);
        }
        return ServiceResult.success(emailDeliver.getId());
    }

    private void originUpdateEmailDeliver(DeliverEmailDeliver emailDeliver, JSONObject param) {
        String emailDeliverId = emailDeliver.getId();
        if (param.containsKey("member_id_list")) {
            //如果参数中有member_id_list就先把原先数据删除
            LambdaQueryWrapper<DeliverEmailDeliverMemberId> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeliverEmailDeliverMemberId::getEmaildeliverId, emailDeliverId);
            deliverEmailDeliverMemberIdMapper.delete(queryWrapper);
        }

        DeliverEmailDeliver deliver = JSON.toJavaObject(param, DeliverEmailDeliver.class);
        deliver.setId(emailDeliverId);
        baseMapper.updateById(deliver);

        List<String> member_id_list = (List<String>) param.get("member_id_list");
        if (CollUtil.isNotEmpty(member_id_list)) {
            batchInsertEmailDeliverMemberId(emailDeliverId, member_id_list);
        }
    }

    private void batchInsertEmailDeliverMemberId(String emailDeliverId, List<String> member_id_list) {
        if (CollectionUtils.isNotEmpty(member_id_list)) {
            List<DeliverEmailDeliverMemberId> list = member_id_list.stream().map(itd -> {
                DeliverEmailDeliverMemberId insertObj = new DeliverEmailDeliverMemberId();
                insertObj.setMemberId(itd);
                insertObj.setEmaildeliverId(emailDeliverId);
                return insertObj;
            }).collect(Collectors.toList());

            if (!list.isEmpty()) {
                deliverEmailDeliverMemberIdMapper.insertBatchSomeColumn(list);
            }
        }
    }


    private ServiceResult<?> beforeDeliverEmailDeliver(DeliverEmailDeliver emailDeliver, JSONObject
            param, DeliverDeliver deliver, Boolean deliver_check, Date delayDate) {
        String deliverId = emailDeliver.getDeliverId();
        Integer isUpload = emailDeliver.getIsUpload();
        param.put("is_upload", isUpload);
        param.put("is_sync_mem", emailDeliver.getIsSyncMem());
        String filterParams = emailDeliver.getFilterParams();
        param.put("filter_params", filterParams);
        if (Objects.equals(1, isUpload)) {
            // 处理随机投放
            JSONObject randomSampling = param.getJSONObject("random_sampling");
            param.put("primary_key", "email");
            //同步名单联系人
            if (Objects.equals(1, param.get("is_sync_mem"))) {
                List<String> memberIdList = memberGrpcClient.importDeliverMember(SecurityContextHolder.getOrgId(), deliverId, "email");
                if (Objects.nonNull(randomSampling) && !randomSampling.isEmpty()) {
                    int size = memberIdList.size();
                    // 按数量或者比例 应该随机得到的联系人数量
                    ServiceResult<Integer> selectNumsResult = dealRandomSampling(randomSampling, size);
                    if (!selectNumsResult.isSuccess()) {
                        return ServiceResult.fail(selectNumsResult.getMsg());
                    }
                    Integer selectNum = selectNumsResult.getData();
                    log.info("member.utils random_sampling----->select:{}-----all:{}", selectNum, size);
                    memberIdList = RandomUtil.randomEleList(memberIdList, selectNum);
                    if (log.isInfoEnabled()) {
                        log.info("随机的联系人数量 {} id 是{}", selectNum, memberIdList);
                    }
                }
                param.put("member_id_list", memberIdList);
                //member_id_list 拆表，直接调用model_utils中的方法，关联表不能自动创建数据
                originUpdateEmailDeliver(emailDeliver, param);
            } else {
                // 下载投放上传的联系人excel文件
                //String filePath = ossService.getFilePrefix() + "deliver_member/" + deliverId.trim() + "/投放名单.xlsx";
                String filePath = storageService.getPropertiesValueBy(null, "base-path") + "deliver_member/" + deliverId.trim() + "/投放名单.xlsx";
                log.info("读取文件:{}", filePath);
                List<MemberDeliverDataByEmail> members;
                try {
                    members = this.parseInputStream(filePath);
                } catch (Exception e) {
                    log.error("[deliver] 获取oss文件流失败:url {}", e.getMessage());
                    return ServiceResult.fail(e.getMessage());
                }
                List<String> emailList = members.stream().map(MemberDeliverDataByEmail::getEmail).collect(Collectors.toList());
                Map<String, List<String>> emailContacts = new HashMap<>();
                members.forEach(v -> emailContacts.put(v.getEmail(), Arrays.asList(v.getName(), v.getOrganization())));
                param.put("email_contacts_message", emailContacts);
                int size = emailList.size();
                // 按数量或者比例 应该随机得到的联系人数量
                ServiceResult<Integer> selectNumsResult = dealRandomSampling(randomSampling, size);
                if (!selectNumsResult.isSuccess()) {
                    return ServiceResult.fail(selectNumsResult.getMsg());
                }
                Integer selectNum = selectNumsResult.getData();
                emailList = RandomUtil.randomEleList(emailList, selectNum);
                param.put("email_list", emailList);
                oldUpdateEmailDeliver(emailDeliver.getDeliverId(), param);
            }
        }
        return deliverEmailDeliver(emailDeliver, param, deliver_check, delayDate);
    }

    private ServiceResult<?> deliverEmailDeliver(DeliverEmailDeliver emailDeliver, JSONObject param, Boolean
            deliverCheck, Date delayDate) {
        Integer sType = Optional.ofNullable((Integer) param.get("s_type")).orElse(EMAILRECORD_S_TYPE_DELIVER.getNumber());
        //是否为非催答(投放发送)
        boolean isNoUrge = !sType.equals(EMAILRECORD_S_TYPE_URGE.getNumber());
        LambdaQueryWrapper<DeliverEmailDeliverMemberId> qwrap = new LambdaQueryWrapper<>();
        qwrap.select(DeliverEmailDeliverMemberId::getMemberId);
        qwrap.eq(DeliverEmailDeliverMemberId::getEmaildeliverId, emailDeliver.getId());
        List<DeliverEmailDeliverMemberId> objList = deliverEmailDeliverMemberIdMapper.selectList(qwrap);
        if (objList.size() > 0) {
            List<String> ids = objList.stream().map(DeliverEmailDeliverMemberId::getMemberId).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
            emailDeliver.setMemberIdlist(ids);
        }
        String email_time = new SimpleDateFormat("yyyy年MM月dd日").format(new Date());
        Project project = qdesGrpcClient.getProject(emailDeliver.getSurveyId());
        String projectName = project.getTitle();
        String ques_name = getQdesName(emailDeliver.getSurveyId(), project.getStructId());
        String systematic_name = getSystemName(SecurityContextHolder.getOrgId());
        if (!isNoUrge) {
            //如果params 中有邮件相关信息 则用params中的
            String email_template = param.getString("email_template");
            if (StringUtils.isNotEmpty(email_template)) {
                emailDeliver.setEmailTemplate(email_template);
            }
            String email_subject = param.getString("email_subject");
            if (StringUtils.isNotEmpty(email_subject)) {
                emailDeliver.setEmailSubject(email_subject);
            }
            String mail_from = param.getString("mail_from");
            if (StringUtils.isNotEmpty(mail_from)) {
                emailDeliver.setMailFrom(mail_from);
            }
            String smtp_id = param.getString("smtp_id");
            if (StringUtils.isNotEmpty(smtp_id)) {
                emailDeliver.setSmtpId(smtp_id);
            }
        }
        //Smtp userSmtp = userGrpcClient.getUserSmtpById(emailDeliver.getSmtpId());
        //String mailFrom = StringUtils.isNotEmpty(userSmtp.getSenderName()) ? userSmtp.getSenderName() + "," + userSmtp.getAccount() : userSmtp.getAccount();
        DeliverDeliver deliver = getDeliver(emailDeliver.getDeliverId());
        if (isNoUrge) {
            //如果当前投放是被修改过，导致version不一致直接结束投放
            String paramVersion = param.getString("version");
            String deliverVersion = deliver.getVersion().toString();
            if (StrUtil.isNotBlank(paramVersion) && StrUtil.isNotBlank(deliverVersion)) {
                if (!StrUtil.equals(paramVersion, deliverVersion)) {
                    throw new BusinessException("当前投放version不一致");
                }
            }
        }
        HashMap<String, String> kwargs = new HashMap<>();
        if (deliver.getAwardUseType() == DELIVER_AWARD_USE_TYPE_USE.getNumber()) {
            kwargs.put("awardId", deliver.getAwardId());
        }
        Integer status = deliver.getStatus();
        Boolean flag = null;
        if (isNoUrge) {
            if (Objects.nonNull(deliverCheck) && deliverCheck) {
                if (!DeliverStatusEnum.getDeliverCheck1Value().contains(status)) {
                    return ServiceResult.fail(-1, "当前投放状态错误");
                }
            } else {
                if (DeliverStatusEnum.getDeliverCheck0Value().contains(status)) {
                    return ServiceResult.fail(-1, "当前投放状态错误");
                }
            }
            Integer isUpload = param.getInteger("is_upload");
            flag = (Objects.isNull(isUpload) || isUpload == 0) || Objects.equals(1, param.get("is_sync_mem"));
            if (flag) {
                if (param.containsKey("member_id_list")) {
                    emailDeliver.setMemberIdlist((List<String>) param.get("member_id_list"));
                }
            } else {
                if (CollectionUtils.isEmpty(emailDeliver.getMemberIdlist())) {
                    //新建投放会调用3个接口，循环重试获取member_id_list
                    emailDeliver = retryQueryEmailDeliver(emailDeliver.getId());
                }
            }
        } else {
            if (DeliverStatusEnum.getDeliverCheck3Value().contains(status)) {
                return ServiceResult.fail(-1, "当前投放状态错误");
            }
            if (param.containsKey("member_id_list")) {
                emailDeliver.setMemberIdlist((List<String>) param.get("member_id_list"));
            }
        }
        if (CollectionUtils.isEmpty(emailDeliver.getMemberIdlist())) {
            log.info("邮件投放符合条件联系人的数量为0");
            return ServiceResult.fail(-1, "邮件投放符合条件联系人的数量为0");
        }
        log.info("邮件投放的联系人的数量为:{}", emailDeliver.getMemberIdlist().size());
        Map<String, String> new_link_dict = new HashMap<>();
        //免打扰联系人id
        List<String> no_disturb_member_id_list;
        if (isNoUrge) {
            no_disturb_member_id_list = deliverService.getNodisturbMemberIdByDeliver(deliver.getId()).stream().distinct().collect(Collectors.toList());
        } else {
            //免打扰联系人id从投放联系人中去除
            no_disturb_member_id_list = JSONObject.parseArray(emailDeliver.getNoDisturbMemberIdList(), String.class);
            if (CollectionUtils.isNotEmpty(no_disturb_member_id_list)) {
                //取两者差集及非免打扰的联系人
                emailDeliver.setMemberIdlist((List<String>) CollectionUtils.subtract(emailDeliver.getMemberIdlist(), no_disturb_member_id_list));
            }
            LambdaQueryWrapper<DeliverEmailRecord> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DeliverEmailRecord::getEmailDeliverId, emailDeliver.getId());
            queryWrapper.eq(DeliverEmailRecord::getSType, EMAILRECORD_S_TYPE_DELIVER.getNumber());
            List<DeliverEmailRecord> link_list = deliverEmailRecordMapper.selectList(queryWrapper);
            link_list.forEach(v -> {
                String surveylink = JSONObject.parseObject(v.getParams()).getString("surveylink");
                if (StrUtil.isNotEmpty(surveylink) && ReUtil.isMatch(URL_REGEX, surveylink)) {
                    new_link_dict.put(v.getMemberId(), surveylink);
                }
            });
        }
        log.info("邮件投放免打扰联系人的数量为:{}", no_disturb_member_id_list.size());

        //改成mq消息处理
        log.info("邮件投放发送mq消息start");

        //改成mq处理,比如5000一个mq消息，这样可以几台机器一起消费，执行投放过程
        List<List<String>> list = !isNoUrge || flag ? ListUtil.partition(emailDeliver.getMemberIdlist(), DELIVER_MQ_BATCH_SIZE)
                : ListUtil.partition(JSONArray.parseArray(emailDeliver.getEmailList()).toJavaList(String.class), DELIVER_MQ_BATCH_SIZE);
        log.info("邮件投放{}发送{}条mq消息,每批次{}", deliver.getId(), list.size(), DELIVER_MQ_BATCH_SIZE);
        //生成签名的value不能为null
        kwargs.put("deliver_g_id", Optional.ofNullable(emailDeliver.getDeliverGroupId()).orElse(""));
        for (List<String> subList : list) {
            EmailDeliverMessageDto dto = new EmailDeliverMessageDto();
            dto.setId(emailDeliver.getId());
            dto.setOrgId(emailDeliver.getOrgId());
            dto.setSurveyId(emailDeliver.getSurveyId());
            dto.setDeliverId(emailDeliver.getDeliverId());
            dto.setEmailSubject(emailDeliver.getEmailSubject());
            dto.setEmailTemplateId(emailDeliver.getEmailTemplateId());
            dto.setEmailTemplate(emailDeliver.getEmailTemplate());
            dto.setCheckSubmit(emailDeliver.getCheckSubmit());
            dto.setDeliverGroupId(emailDeliver.getDeliverGroupId());
            dto.setKwargs(kwargs);
            dto.setProjectName(projectName);
            dto.setNoDisturbMemberIdlist(no_disturb_member_id_list);
            dto.setMsgTotal(list.size());
            dto.setSystemName(systematic_name);
            dto.setEmailTime(email_time);
            dto.setQuesName(ques_name);
            dto.setSType(sType);
            dto.setFlag(flag);
            if (!isNoUrge || flag) {
                dto.setMemberIdlist(subList);
            } else {
                dto.setEmailList(subList);
            }
            dto.setEmailContacts((Map<String, List<String>>) param.get("email_contacts_message"));
            //dto.setMailFrom(mailFrom);
            dto.setSmtpId(emailDeliver.getSmtpId());
            dto.setNewLinkDict(new_link_dict);
            dto.setVersion(deliver.getVersion());
            //发送mq消息
            sendDeliverMsg(dto, delayDate);
        }
        log.info("邮件投放发送mq消息end");
        return ServiceResult.success();
    }

    private void oldUpdateEmailDeliver(String emailDeliverId, JSONObject param) {
        DeliverEmailDeliver deliver = JSON.toJavaObject(param, DeliverEmailDeliver.class);
        deliver.setId(emailDeliverId);
        baseMapper.updateById(deliver);
    }

    /**
     * 按数量或者比例 应该随机得到的联系人数量
     *
     * @param randomSampling {'type':'num', 'value':100， 'true_num'}
     * @param size           联系人总数
     * @return
     */
    @Override
    public ServiceResult<Integer> dealRandomSampling(JSONObject randomSampling, int size) {
        if (!randomSampling.containsKey("type") || !randomSampling.containsKey("value") || !randomSampling.containsKey("true_num")) {
            return ServiceResult.fail("random_sampling must contain type and value and true_num");
        }
        List<String> types = new ArrayList<String>() {{
            add("num");
            add("ratio");
        }};
        String type = randomSampling.getString("type");
        if (!types.contains(type)) {
            return ServiceResult.fail("random_sampling invalid type");
        }
        Integer selectNums;
        try {
            selectNums = randomSampling.getInteger("true_num");
        } catch (Exception e) {
            log.error("true_num is not a num", e);
            return ServiceResult.fail("true_num is not a num");
        }
        if (selectNums < 0) {
            return ServiceResult.fail("true_num not in range");
        }
        if (selectNums > size) {
            selectNums = size;
        }
        return ServiceResult.success(selectNums);
    }

    @Override
    public List<MemberDeliverDataByEmail> parseInputStream(String excelFilePath) {
        DynamicEasyExcelImportUtil.EasyExcelListener<MemberDeliverDataByEmail> excelListener = new DynamicEasyExcelImportUtil.EasyExcelListener<>();
        //InputStream is = ossService.downloadFile(excelFilePath);
        //InputStream is = storageService.downloadFile(excelFilePath);
        InputStream is = new ByteArrayInputStream(storageService.downloadByUrl(storageService.getPropertiesValueBy(null, "domain") + excelFilePath).bytes());
        // 读取数据
        EasyExcel.read(is, MemberDeliverDataByEmail.class, excelListener).sheet().doRead();
        if (org.springframework.util.CollectionUtils.isEmpty(excelListener.getResult())) {
            return Collections.emptyList();
        }

        return new ArrayList<>(excelListener.getResult());
    }

    /**
     * 内容html标签去除
     *
     * @param smsContent 短信内容
     * @return 短信内容
     */
    public static String contentHtmlLabelsRegexp(String smsContent) {
        Matcher matcher = P_PATTERN.matcher(smsContent);
        smsContent = matcher.replaceAll("");
        return smsContent;
    }

    /**
     * 获取问卷名称
     *
     * @param projectId 项目id
     * @param qStructId 问卷结构数据id
     * @return 问卷名称
     */
    @Override
    public String getQdesName(String projectId, String qStructId) {
        String qdesName = StrUtil.EMPTY;
        if (StringUtils.isBlank(qStructId)) {
            Project project = qdesGrpcClient.getProject(projectId);
            if (Objects.isNull(project)) {
                return StrUtil.EMPTY;
            } else {
                try {
                    qStructId = project.getStructId();
                } catch (Exception e) {
                    log.error("[award] sms 获取问卷结果数据struct_id失败, projectId={}: ", projectId, e);
                    return StrUtil.EMPTY;
                }
            }
        }
        if (StringUtils.isNotBlank(qStructId)) {
            QStruct qStruct = qdesGrpcClient.getQStruct(qStructId);
            if (Objects.isNull(qStruct)) {
                return StrUtil.EMPTY;
            } else {
                // 问卷结构数据
                String data = null;
                try {
                    data = qStruct.getData();
                    log.info("[award] sendSms 问卷结构数据: data={}, projectId={}, qStructId={}", data, projectId, qStructId);
                    JSONObject jsonObject = JSONObject.parseObject(data);
                    qdesName = jsonObject.getJSONObject("desc_begin_page").getJSONObject("content").getString("text");
                    qdesName = contentHtmlLabelsRegexp(qdesName);
                } catch (Exception e) {
                    log.error("[award] sendSms 解析问卷结构数据获取问卷名称失败: jsonData={}, projectId={}, qStructId={}", data, projectId, qStructId, e);
                    return StrUtil.EMPTY;
                }
            }
        }
        return qdesName;
    }

    /**
     * 获取系统名称
     *
     * @param orgId 组织id
     * @return 系统名称
     */
    @Override
    public String getSystemName(String orgId) {
        String systemName = "倍市得CEM";
        OrgInfoDto organization = userGrpcClient.getOrganization(orgId);
        if (Objects.nonNull(organization)) {
            // 组织信息
            String skin = null;
            try {
                skin = organization.getSkin();
                if (log.isInfoEnabled()) {
                    log.info("[deliver] 组织皮肤信息: skin={}, orgId={}", skin, orgId);
                }
                if (StrUtil.isNotBlank(skin)) {
                    JSONObject jsonObject = JSONObject.parseObject(skin);
                    // 自定义的系统名称是否使用
                    Boolean status = jsonObject.getBoolean("status");
                    if (Objects.nonNull(status) && status) {
                        systemName = Objects.isNull(jsonObject.getString("name")) ? "倍市得CEM" : jsonObject.getString("name");
                    }
                }
            } catch (Exception e) {
                log.error("[deliver] 获取组织皮肤信息获取系统名称失败: jsonData={}, orgId={} ", skin, orgId, e);
            }
        }
        return systemName;
    }

    private DeliverEmailDeliver retryQueryEmailDeliver(String id) {
        //表示哪些异常需要重试
        //key一定要为Throwable异常的子类    Class<? extends Throwable>
        //value为true表示需要重试
        Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
        // 1 添加异常的处理结果 true为需要重试 false为不需要重试
        exceptionMap.put(BusinessException.class, true);

        // 2 构建重试模板实例
        RetryTemplate retryTemplate = new RetryTemplate();

        // 3 设置重试回退操作策略  设置重试间隔时间
        ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
        backOffPolicy.setInitialInterval(1000);
        backOffPolicy.setMultiplier(1.5);
        backOffPolicy.setMaxInterval(60000);

        // 4 设置重试策略  设置重试次数 设置异常处理结果
        SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(3, exceptionMap);

        //5 重试模板添加重试策略 添加回退操作策略
        retryTemplate.setRetryPolicy(retryPolicy);
        retryTemplate.setBackOffPolicy(backOffPolicy);

        // 6 调用方法
        return retryTemplate.execute(
                // RetryCallback 重试回调方法
                retryCallback -> queryEmailDeliverAndMemberIdList(id),
                // RecoveryCallback 异常回调方法
                recoveryCallback -> {
                    Throwable throwable = recoveryCallback.getLastThrowable();
                    log.error("retryQueryEmailDeliver失败, id: {}, retryCount: {}", id, recoveryCallback.getRetryCount(), throwable);
                    throw new BusinessException("邮件投放缺少关键参数member_id_list和mp_template_id，无法执行异步任务发送消息");
                });
    }

    private DeliverEmailDeliver queryEmailDeliverAndMemberIdList(String id) {
        DeliverEmailDeliver emailDeliver = baseMapper.selectById(id);
        if (StrUtil.isEmpty(emailDeliver.getEmailTemplateId())) {
            throw new BusinessException("邮件投放更新还没结束，稍后重试查询1");
        }

        LambdaQueryWrapper<DeliverEmailDeliverMemberId> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(DeliverEmailDeliverMemberId::getMemberId);
        wrapper.eq(DeliverEmailDeliverMemberId::getEmaildeliverId, emailDeliver.getId());
        List<DeliverEmailDeliverMemberId> objList = deliverEmailDeliverMemberIdMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(objList)) {
            throw new BusinessException("邮件投放更新还没结束，稍后重试查询2");
        }

        List<String> ids = objList.stream().map(DeliverEmailDeliverMemberId::getMemberId).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
        emailDeliver.setMemberIdlist(ids);
        return emailDeliver;
    }

    private void sendDeliverMsg(EmailDeliverMessageDto dto, Date delayDate) {
        if (Objects.isNull(delayDate)) {
            //立即投放
            deliverMessageSendService.emailDeliverSend(dto);
        } else {
            //延迟投放
            deliverMessageSendService.emailDeliverSend(dto, delayDate);
        }
    }

    @Override
    public ServiceResult<?> editEmailDelivers(String id, JSONObject param) {
        DeliverEmailDeliver emailDeliver = baseMapper.selectById(id);
        DeliverDeliver deliver = getDeliver(emailDeliver.getDeliverId());
        if (Objects.equals(emailDeliver.getIsCheck(), 1)) {
            //增加未投放可以编辑
            if (!DeliverStatusEnum.getDeliverCheck2Value().contains(deliver.getStatus())) {
                return ServiceResult.fail(STATUS_CHANGED, "投放状态不支持编辑");
            }
        } else {
            if (!Objects.equals(DELIVER_STATUS_STOP.getValue(), deliver.getStatus())) {
                return ServiceResult.fail(STATUS_CHANGED, "投放状态不支持编辑");
            }
        }
        return editEmailDeliver(emailDeliver, param);
    }

    private ServiceResult<?> editEmailDeliver(DeliverEmailDeliver emailDeliver, JSONObject param) {
        String orgId = SecurityContextHolder.getOrgId();
        if (Objects.equals(emailDeliver.getIsCheck(), 0) && Objects.equals(emailDeliver.getIsDelay(), 1) && Objects.equals(param.get("is_delay"), 0)) {
            param.put("_sign", true);
        }
        param.put("is_check", param.getInteger("is_check") == 1);
        param.put("is_delay", param.getInteger("is_delay") == 1);
        //发送问卷时需要携带唯一链接，在start接口进行修改
        Integer survey_submit_type = (Integer) param.getOrDefault("survey_submit_type", LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex());
        if (survey_submit_type.equals(LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex())) {
            DeliverDeliverGroup deliverDeliverGroup = deliverDeliverGroupMapper.selectById(emailDeliver.getDeliverGroupId());
            if (Objects.isNull(deliverDeliverGroup)) {
                return ServiceResult.fail(-1, "投放组不存在");
            }
        }
        param.put("deliver_id", emailDeliver.getDeliverId());
        String survey_id = param.getString("survey_id");
        String deliverId = emailDeliver.getDeliverId();
        delDeliverFromGroup(emailDeliver.getDeliverId(), survey_id);
        if (survey_submit_type.equals(LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex())) {
            String deliverGroupId = createDeliverGroup(orgId, survey_id, Collections.singletonList(deliverId));
            log.info("创建投放组成功");
            param.put("deliver_group_id", deliverGroupId);
        } else if (survey_submit_type.equals(LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex())) {
            addDeliverToGroup(deliverId, survey_id, emailDeliver.getDeliverGroupId());
            param.put("deliver_group_id", param.getString("deliver_g_id"));
        } else {
            param.put("deliver_group_id", null);
        }
        //编辑时清空之前的 member_id_list，避免投放时联系人列表是未更新的。
        param.put("member_id_list", new ArrayList<>());
        originUpdateEmailDeliver(emailDeliver, param);
        updateEmailDeliver(emailDeliver, param);
        JSONObject ret = new JSONObject();
        ret.put("id", deliverId);
        ret.put("status", true);
        return ServiceResult.success(ret);
    }

    /**
     * 增加投放到投放组
     *
     * @param deliverId
     * @param surveyId
     * @param deliverGroupId
     */
    @Override
    public void addDeliverToGroup(String deliverId, String surveyId, String deliverGroupId) {
        DeliverGroupVo deliverGroupVo = deliverDeliverGroupMapper.getDeliverGroup(deliverGroupId);
        if (Objects.isNull(deliverGroupVo)) {
            throw new BusinessException(String.valueOf(ResourceErrorCodeEnum.NOT_FOUND), "投放组不存在");
        }
        List<DeliverDeliverGroupDeliver> deliverList = Optional.ofNullable(deliverGroupVo.getDeliverList()).orElse(new ArrayList<>());
        DeliverDeliverGroupDeliver deliverGroupDeliver = new DeliverDeliverGroupDeliver();
        deliverGroupDeliver.setDeliverId(deliverId);
        deliverList.add(deliverGroupDeliver);
        deliverGroupVo.setDeliverList(deliverList);
        originUpdateDeliverGroup(deliverGroupVo, surveyId);
    }

    /**
     * 把投放从之前加入到的投放组中去掉
     *
     * @param deliverId
     * @param survey_id
     */
    @Override
    public void delDeliverFromGroup(String deliverId, String survey_id) {
        LambdaQueryWrapper<DeliverDeliverGroup> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeliverDeliverGroup::getSurveyId, survey_id);
        List<String> delete_list = deliverDeliverGroupMapper.selectList(wrapper).stream().map(DeliverDeliverGroup::getId).distinct().collect(Collectors.toList());
        LambdaQueryWrapper<DeliverDeliverGroupDeliver> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(DeliverDeliverGroupDeliver::getDeliverGroupId, delete_list).eq(DeliverDeliverGroupDeliver::getDeliverId, deliverId);
        deliverDeliverGroupDeliverMapper.delete(lambdaQueryWrapper);
    }

    @Override
    public void emailDeliverExport(JSONObject param, HttpServletResponse response, DeliverEmailDeliver
            emailDeliver, DeliverDeliver deliver) {
        Integer check_submit = emailDeliver.getCheckSubmit();
        String project_id = param.getString("project_id");
        List<JSONObject> record_list;
        Map<String, List<Integer>> member_maps = new HashMap<>();
        if (param.containsKey("member_ids")) {
            List<String> member_ids = param.getJSONArray("member_ids").toJavaList(String.class);
            if (CollectionUtils.isEmpty(member_ids)) {
                throw new BusinessException("缺少联系人member_ids");
            }
            record_list = getEmailRecordBySelect(emailDeliver, project_id, member_ids, member_maps);
        } else {
            List<String> exclude_member_ids = null;
            if (param.containsKey("exclude_member_ids")) {
                exclude_member_ids = param.getJSONArray("exclude_member_ids").toJavaList(String.class);
            }

            JSONObject filter_params = param.getJSONObject("filter_params");
            record_list = getEmailRecordByFilterParams(emailDeliver, filter_params, exclude_member_ids, project_id, member_maps);
        }
        boolean display_contact;
        if (!member_maps.isEmpty()) {
            display_contact = memberGrpcClient.checkDisplayRangePermission(SecurityContextHolder.getOrgId(), SecurityContextHolder.getUserId(), new ArrayList<>(member_maps.keySet()).get(0));
        } else {
            display_contact = true;
        }
        //导出
        String ossUrl = exportExcelEmailRecordByIds(record_list, member_maps, display_contact, check_submit, response);
        log.info("邮件投放导出文件路径={}", ossUrl);
    }

    /**
     * 根据选中的联系人获取投放记录
     *
     * @param emailDeliver
     * @param project_id
     * @param member_ids
     * @return
     */
    private List<JSONObject> getEmailRecordBySelect(DeliverEmailDeliver emailDeliver, String
            project_id, List<String> member_ids, Map<String, List<Integer>> member_maps) {
        if (Objects.nonNull(member_maps)) {
            Map<String, List<Integer>> tmp = getDeliverDataMember(null, null, emailDeliver.getDeliverGroupId(), emailDeliver.getDeliverId(), member_ids);
            member_maps.putAll(tmp);
        } else {
            member_maps = getDeliverDataMember(null, null, emailDeliver.getDeliverGroupId(), emailDeliver.getDeliverId(), member_ids);
        }

        List<JSONObject> record_list = new ArrayList<>();
        Map<String, Integer> member_resp_maps = new HashMap<>();
        Integer check_submit = emailDeliver.getCheckSubmit();
        if (check_submit.equals(0)) {
            for (String member_id : member_ids) {
                //Integer finished = surveyGrpcClient.getDeliverMemberRespTotalCount(emailDeliver.getDeliverId(), member_id, project_id);
                Integer finished = surveyGrpcClient.getDeliverRspdAmount(emailDeliver.getDeliverId(), null, null, member_id, RESPONDENT_STATUS_FINISH.getValue(), null, project_id);
                member_resp_maps.put(member_id, finished);
            }
        } else {
            for (String member_id : member_ids) {
                //Integer survey_resp_status = surveyGrpcClient.getDeliverRespStatus(emailDeliver.getDeliverId(), member_id, project_id);
                Integer survey_resp_status = surveyGrpcClient.getDeliverRspdStatus(emailDeliver.getDeliverId(), member_id, null, null, project_id);
                member_resp_maps.put(member_id, survey_resp_status);
            }
        }

        LambdaQueryWrapper<DeliverEmailRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByAsc(DeliverEmailRecord::getId);
        queryWrapper.in(DeliverEmailRecord::getMemberId, member_ids);
        queryWrapper.eq(DeliverEmailRecord::getEmailDeliverId, emailDeliver.getId());
        List<DeliverEmailRecord> email_records = deliverEmailRecordMapper.selectList(queryWrapper);
        log.info("email_records-->>{}", email_records);
        record2JsonObject(record_list, check_submit, member_resp_maps, email_records, member_maps);
        return record_list;
    }

    private void record2JsonObject(List<JSONObject> record_list, Integer
            check_submit, Map<String, Integer> member_resp_maps, List<DeliverEmailRecord> email_records, Map<String, List<Integer>> member_maps) {
        ArrayList<String> email_record_member_id = new ArrayList<>();
        for (DeliverEmailRecord record : email_records) {
            String member_id = record.getMemberId();
            if (email_record_member_id.contains(member_id)) {
                continue;
            } else {
                email_record_member_id.add(member_id);
            }
            JSONObject item = new JSONObject();
            item.put("member_id", record.getMemberId());
            item.put("username", record.getUsername());
            item.put("email", record.getEmail());
            if (check_submit.equals(0)) {
                item.put("finished", Optional.ofNullable(member_resp_maps.get(member_id)).orElse(0));
            } else {
                item.put("survey_resp_status", Optional.ofNullable(member_resp_maps.get(member_id)).orElse(RESPONDENT_STATUS_NOTSTART.getValue()));
            }
            item.put("surveylink", JSONObject.parseObject(record.getParams()).getString("surveylink"));
            List<Integer> nums = member_maps.getOrDefault("member_id", Arrays.asList(0, 0, DELIVERSURVEYDATA_SURVEY_STATUS_UNANSWER.getValue()));
            item.put("survey_nums", nums.get(2));
            item.put("survey_status", nums.get(1));
            item.put("urge_nums", nums.get(0));
            item.put("send_status", EmailRecordStatusEnum.getDescByValue(record.getStatus()));
            item.put("send_time", record.getCreatedDt().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
            record_list.add(item);
        }
        //反转
        Collections.reverse(record_list);
    }

    /**
     * 根据过滤条件筛选联系人投放记录
     *
     * @param emailDeliver
     * @param filter_params
     * @param exclude_member_ids
     * @param project_id
     * @param member_maps
     * @return
     */
    private List<JSONObject> getEmailRecordByFilterParams(DeliverEmailDeliver emailDeliver, JSONObject
            filter_params, List<String> exclude_member_ids, String
                                                                  project_id, Map<String, List<Integer>> member_maps) {
        List<JSONObject> record_list = emailRecordsData(emailDeliver, filter_params, project_id, member_maps, true);
        if (CollectionUtils.isEmpty(exclude_member_ids)) {
            return record_list;
        }
        return record_list.stream().filter(one -> !exclude_member_ids.contains(one.getString("member_id"))).collect(Collectors.toList());
    }

    private List<JSONObject> emailRecordsData(DeliverEmailDeliver emailDeliver, JSONObject filter_params, String
            project_id, Map<String, List<Integer>> member_maps, boolean use_aggergate) {
        Boolean urged = filter_params.getBoolean("urged");
        String status = filter_params.getString("status");
        String survey_status = filter_params.getString("survey_status");
        String survey_resp_status_arg = filter_params.getString("survey_resp_status");
        String search = filter_params.getString("search");
        String sType = filter_params.getString("s_type");
        String deliver_id = emailDeliver.getDeliverId();
        String deliverGroupId = emailDeliver.getDeliverGroupId();
        Integer check_submit = emailDeliver.getCheckSubmit();
        if (Objects.nonNull(member_maps)) {
            Map<String, List<Integer>> tmp = getDeliverDataMember(urged, survey_status, deliverGroupId, deliver_id, null);
            member_maps.putAll(tmp);
        } else {
            member_maps = getDeliverDataMember(urged, survey_status, deliverGroupId, deliver_id, null);
        }
        Set<String> member_surveydata_ids = member_maps.keySet();
        List<String> member_ids;
        if (urged != null) {
            member_ids = new ArrayList<>(member_surveydata_ids);
        } else {
            member_ids = deliverService.getDeliverMemberIdList(deliver_id, DeliverTtypeEnum.DELIVER_TTYPE_EMAIL);
        }
        Map<String, Integer> member_resp_maps = new HashMap<>();
        deliverService.getMemberRespMaps(project_id, survey_resp_status_arg, deliver_id, check_submit, member_resp_maps, member_ids);
        Set<String> member_resp_ids = member_resp_maps.keySet();

        LambdaQueryWrapper<DeliverEmailRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeliverEmailRecord::getEmailDeliverId, emailDeliver.getId());
        wrapper.eq(StrUtil.isNotBlank(status), DeliverEmailRecord::getStatus, status);
        wrapper.and(StrUtil.isNotBlank(search), wrap -> wrap.like(DeliverEmailRecord::getUsername, search).or().like(DeliverEmailRecord::getEmail, search));

        if (urged != null || StrUtil.isNotBlank(survey_resp_status_arg)) {
            member_ids = new ArrayList<>(CollectionUtils.intersection(member_surveydata_ids, new HashSet<>(member_resp_ids)));
            wrapper.in(!CollectionUtils.isEmpty(member_ids), DeliverEmailRecord::getMemberId, member_ids);
        }
        wrapper.eq(Objects.nonNull(sType), DeliverEmailRecord::getSType, sType);
        if (use_aggergate) {
            List<JSONObject> record_list = new ArrayList<>();
            wrapper.orderByAsc(DeliverEmailRecord::getId);
            List<DeliverEmailRecord> records = deliverEmailRecordMapper.selectList(wrapper);
            record2JsonObject(record_list, check_submit, member_resp_maps, records, member_maps);
            return record_list;
        }
        wrapper.orderByDesc(DeliverEmailRecord::getCreatedDt);
        return deliverEmailRecordMapper.selectList(wrapper).stream().map(one -> (JSONObject) JSONObject.toJSON(one)).collect(Collectors.toList());
    }

    /**
     * 根据投放发送记录id导出excel格式
     *
     * @param recordList
     * @param member_maps
     * @param display_contact
     * @param check_submit
     * @param response
     * @return
     */
    private String exportExcelEmailRecordByIds(List<JSONObject> recordList, Map<String, List<Integer>> member_maps, boolean display_contact,
                                               Integer check_submit, HttpServletResponse response) {
        if (CollectionUtils.isEmpty(recordList)) {
            return "没有数据";
        }
        List<List<List<String>>> head = new ArrayList<>();
        List<List<String>> headRowList = new ArrayList<>();

        List<List<List<Object>>> exportDataList = new ArrayList<>();
        List<List<Object>> rowList = new ArrayList<>();
        Set<String> member_id_set = new HashSet<>();
        for (JSONObject record : recordList) {
            String member_id = record.getString("member_id");
            if (member_id_set.contains(member_id)) {
                continue;
            }
            member_id_set.add(member_id);
            List<Object> item = new ArrayList<>();
            item.add(record.getString("username"));
            String email = record.getString("email");
            if (!display_contact && StringUtils.isNotEmpty(email)) {
                email = hideEmail(email, true);
            }
            item.add(email);
            item.add(record.getString("surveylink"));
            item.add(record.getString("send_status"));
            item.add(record.getString("send_time"));
            if (check_submit.equals(1)) {
                item.add(RespondentStatusEnum.getDescByValue(record.getIntValue("survey_resp_status")));
            } else {
                item.add(record.getString("finished"));
            }
            item.add(member_maps.get(member_id).get(0));
            rowList.add(item);
        }
        if (check_submit.equals(1)) {
            getTitleHead(headRowList, Stream.of("姓名", "邮箱", "问卷链接", "发送状态", "发送时间", "答卷状态", "催答次数").collect(Collectors.toList()));
        } else {
            getTitleHead(headRowList, Stream.of("姓名", "邮箱", "问卷链接", "发送状态", "发送时间", "成功完成答卷", "催答次数").collect(Collectors.toList()));
        }
        head.add(headRowList);
        exportDataList.add(rowList);
        // sheet页名称-自定义，如果没有则传空
        List<String> sheetNameList = Stream.of("sheet1").collect(Collectors.toList());
        String ossPath = OssPathEnum.TEMP_DELIVER.getPath() + EMAILDELIVER_EXPORT + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN) + SEPARATOR;
        //return ExcelExportUtil.exportWithDynamicData2("投放清单明细", head, exportDataList, sheetNameList, response, ossService, ossPath, OssPathEnum.TEMP_DELIVER);
        ///return ExcelExportUtil.exportWithDynamicData2("投放清单明细", head, exportDataList, sheetNameList, response, , ossPath, OssPathEnum.TEMP_DELIVER);
        return deliverService.exportWithDynamicData("投放清单明细", head, exportDataList, sheetNameList, response, ossPath);
    }

    @Override
    public void getTitleHead(List<List<String>> headRowList, List<String> titelList) {
        for (String title : titelList) {
            List<String> rowHead = new ArrayList<>();
            rowHead.add(title);
            headRowList.add(rowHead);
        }
    }

    @Override
    public ServiceResult<?> emailDeliverAgain(String id, JSONObject param, DeliverEmailDeliver emailDeliver) {
        String orgId = SecurityContextHolder.getOrgId();
        String userId = SecurityContextHolder.getUserId();
        List<String> member_ids;
        if (param.containsKey("member_ids")) {
            member_ids = param.getJSONArray("member_ids").toJavaList(String.class);
            if (CollectionUtils.isEmpty(member_ids)) {
                return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "缺少联系人");
            }
            member_ids = filterDeliverAgainMembers(member_ids, false, false);
        } else {
            JSONObject filter_params = (JSONObject) param.getOrDefault("filter_params", new JSONObject());
            List<String> exclude_member_ids = CollectionUtils.isEmpty(param.getJSONArray("exclude_member_ids")) ? Collections.emptyList() : param.getJSONArray("exclude_member_ids").toJavaList(String.class);

            //勾选全部重新投放不可选择"黑名单拦截"、"邮件退订"发送状态
            String status = filter_params.getString("status");
            if (String.valueOf(EmailRecordStatusEnum.EMAILRECORD_STATUS_MEMBER_BLACKLIST.getValue()).equals(status)) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "黑名单用户无法重新投放");
            } else if (String.valueOf(EmailRecordStatusEnum.EMAILRECORD_STATUS_EMAIL_UNSUBSCRIBE.getValue()).equals(status)) {
                return ServiceResult.fail(ReqErrorCodeEnum.PARAM_RANGE, "退订邮件用户无法重新投放");
            }
            member_ids = emailDeliverRecordMembers(emailDeliver, filter_params, exclude_member_ids, id);
            if (CollectionUtils.isNotEmpty(member_ids)) {
                member_ids = filterDeliverAgainMembers(member_ids, false, false);
            }
        }
        String new_deliver_id = emailDeliverRecastBySelect(orgId, emailDeliver, id, member_ids, userId);
        DeliverDeliver deliver = deliverDeliverMapper.selectById(new_deliver_id);
        Map<String, String> res = new HashMap<>();
        res.put("id", new_deliver_id);
        res.put("deliver_name", deliver.getName());
        return ServiceResult.success(res);
    }

    /**
     * 投放对黑名单或邮件退订的联系人无法催答
     * 先判断黑名单状态 再判断邮件订阅状态
     * 全是黑名单则提示"黑名单用户无法催答"
     * 全是邮件退订则提示"退订邮件用户无法催答"
     * 二者都有则提示"没有可催答的联系人"
     *
     * @param member_ids
     * @param filter_blacklist   是否过滤加入黑名单的联系人
     * @param filter_unsubscribe 是否过滤邮件退订的联系人
     */
    @Override
    public List<String> filterDeliverUrgeMembers(List<String> member_ids, boolean filter_blacklist,
                                                 boolean filter_unsubscribe) {
        if (CollectionUtils.isEmpty(member_ids)) {
            return member_ids;
        }
        List<MemberDto> member_list = memberGrpcClient.listMembersByIds(member_ids);
        if (CollectionUtils.isEmpty(member_list)) {
            return Collections.emptyList();
        }
        List<String> filter_member_list;
        boolean has_blacklist_member;
        if (filter_blacklist) {
            //过滤加入黑名单的联系人
            filter_member_list = member_list.stream().filter(v -> !v.getMemberDeliveryStatus().equals(MemberDeliveryStatus.MEMBER_DELIVERY_STATUS_DISABLED.getValue())).map(MemberDto::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(filter_member_list)) {
                throw new BusinessException(String.valueOf(ResourceErrorCodeEnum.STATUS_CHANGED), "黑名单用户无法催答");
            }
            has_blacklist_member = member_list.size() > filter_member_list.size();
        } else {
            filter_member_list = member_list.stream().map(MemberDto::getId).collect(Collectors.toList());
            has_blacklist_member = false;
        }
        if (filter_unsubscribe) {
            filter_member_list = member_list.stream().filter(v -> !v.getSubscribeStatus().equals(MemberSubscribeStatus.MEMBER_SUBSCRIBE_STATUS_UNSUBSCRIBE.getValue())).map(MemberDto::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(filter_member_list)) {
                if (has_blacklist_member) {
                    throw new BusinessException("没有可催答的联系人");
                } else {
                    throw new BusinessException("退订邮件用户无法催答");
                }
            }
        }
        return filter_member_list;
    }


    /**
     * 返回邮件投放中的符合条件的联系人
     *
     * @param emailDeliver
     * @param filter_params
     * @param exclude_member_ids
     * @param project_id
     */
    private List<String> emailDeliverRecordMembers(DeliverEmailDeliver emailDeliver, JSONObject
            filter_params, List<String> exclude_member_ids, String project_id) {
        List<JSONObject> tmp = emailRecordsData(emailDeliver, filter_params, project_id, null, false);
        List<DeliverEmailRecord> email_records = JSONObject.parseArray(JSONArray.toJSONString(tmp), DeliverEmailRecord.class);
        return email_records.stream().map(DeliverEmailRecord::getMemberId).filter(v -> !exclude_member_ids.contains(v)).distinct().collect(Collectors.toList());
    }

    /**
     * 选中联系人的邮件重新投放
     *
     * @param orgId
     * @param emailDeliver
     * @param id
     * @param member_ids
     * @param userId
     * @return
     */
    private String emailDeliverRecastBySelect(String orgId, DeliverEmailDeliver emailDeliver, String
            id, List<String> member_ids, String userId) {
        DeliverDeliver deliver = getDeliver(emailDeliver.getDeliverId());
        DeliverRecast deliverRecast = getOneRecast(emailDeliver.getDeliverId());
        DeliverDeliverGroup deliverDeliverGroup = StrUtil.isNotEmpty(emailDeliver.getDeliverGroupId()) ? originGetDeliverGroup(emailDeliver.getDeliverGroupId()) : null;
        String deliverGroupId = Optional.ofNullable(deliverDeliverGroup).map(DeliverDeliverGroup::getId).orElse(null);
        String recast_nums = Objects.isNull(deliverRecast) ? "1" : String.valueOf(JSON.parseArray(deliverRecast.getChildrenDeliver()).size() + 1);
        List<String> new_member_list = new ArrayList<>();
        member_ids.forEach(v -> {
            if (checkMemberDeliverUrgeStatus(v, deliverGroupId, deliver.getId())) {
                new_member_list.add(v);
            }
        });
        if (new_member_list.isEmpty()) {
            throw new BusinessException(String.valueOf(ResourceErrorCodeEnum.STATUS_CHANGED.getCode()), "没有可重新投放的联系人");
        }
        JSONObject new_deliver_params = buildRecastParams(deliver, recast_nums, deliverDeliverGroup, emailDeliver, null);
        new_deliver_params.put("member_id_list", new_member_list);
        new_deliver_params.put("orgId", orgId);
        new_deliver_params.put("user_id", userId);
        log.info("开始创建邮件投放{}", new_deliver_params);
        String new_deliver_id = createEmailDeliver(JSON.toJavaObject(new_deliver_params, EmailDeliversParamAgain.class));
        createOrUpdateRecast(orgId, emailDeliver.getDeliverId(), new_deliver_id);
        DeliverDeliver deliverRes = deliverDeliverMapper.selectById(new_deliver_id);
        triggerDeliverCheckStatus(deliverRes, "done");
        return new_deliver_id;
    }

    @Override
    public void triggerDeliverCheckStatus(DeliverDeliver deliverRes, String action) {
        //Integer old_status = deliverRes.getStatus();
        if (Arrays.asList("done", "start", "review_success").contains(action)) {
            //邮件投放固定返回true
            /*boolean status = deliverDeliverTriggerService.checkDeliverStatus(deliverRes);
            if (status) {
                triggerDeliverStatus(deliverRes, action);
            } else {
                throw new BusinessException(String.valueOf(ValidationErrorCodeEnum.DELIVER_INVALIDATE.getCode()), "当前设置不完善，无法投放!");
            }*/
            triggerDeliverStatus(deliverRes, action);
        }
        //return old_status;
    }

    @Override
    public void createOrUpdateRecast(String orgId, String deliverId, String new_deliver_id) {
        LambdaQueryWrapper<DeliverRecast> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverRecast::getOrgId, orgId);
        queryWrapper.eq(DeliverRecast::getParentDeliver, deliverId);
        DeliverRecast deliverRecast = deliverRecastMapper.selectOne(queryWrapper);
        if (Objects.isNull(deliverRecast)) {
            deliverRecast = new DeliverRecast();
            deliverRecast.setId(new ObjectId().toHexString());
            deliverRecast.setOrgId(orgId);
            deliverRecast.setParentDeliver(deliverId);
            deliverRecast.setChildrenDeliver(JSONObject.toJSONString(Arrays.asList(new_deliver_id)));
            deliverRecastMapper.insert(deliverRecast);
        } else {
            JSONArray children_deliver = JSON.parseArray(deliverRecast.getChildrenDeliver());
            children_deliver.add(new_deliver_id);
            deliverRecast.setChildrenDeliver(children_deliver.toJSONString());
            deliverRecastMapper.updateById(deliverRecast);
        }
        log.info("重新投放的id为：{}", deliverRecast.getId());
    }

    /**
     * 检查联系人的答卷状态, 投放组中检查的是所有投放是否答题
     *
     * @param member_id
     * @param deliverGroupId
     * @param deliver_id
     */
    @Override
    public boolean checkMemberDeliverUrgeStatus(String member_id, String deliverGroupId, String deliver_id) {
        LambdaQueryWrapper<DeliverDeliverSurveyData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverDeliverSurveyData::getMemberId, member_id);
        if (StrUtil.isNotEmpty(deliverGroupId)) {
            queryWrapper.eq(DeliverDeliverSurveyData::getDeliverGroupId, deliverGroupId);
        } else {
            queryWrapper.eq(DeliverDeliverSurveyData::getDeliverId, deliver_id);
        }
        queryWrapper.eq(DeliverDeliverSurveyData::getSurveyStatus, DeliverSurveyDataSurveyStatusEnum.DELIVERSURVEYDATA_SURVEY_STATUS_SUBMIT.getValue());
        DeliverDeliverSurveyData deliverDeliverSurveyData = deliverSurveyDataMapper.selectOne(queryWrapper);
        return Objects.nonNull(deliverDeliverSurveyData);
    }

    /**
     * 构建新的投放参数
     *
     * @param deliver
     * @param recast_nums
     * @param deliverDeliverGroup
     * @param emailDeliver
     * @param smsDeliver
     */
    @Override
    public JSONObject buildRecastParams(DeliverDeliver deliver, String recast_nums, DeliverDeliverGroup
            deliverDeliverGroup, DeliverEmailDeliver emailDeliver, DeliverSmsDeliver smsDeliver) {
        JSONObject new_deliver_params = new JSONObject();
        JSONObject old_deliver_params = new JSONObject();
        if (deliver.getTtype().equals(DELIVER_TTYPE_SMS.getValue())) {
            old_deliver_params.put("sms_template_id", smsDeliver.getSmsTemplateId());
            old_deliver_params.put("check_submit", smsDeliver.getCheckSubmit());
            old_deliver_params.put("survey_id", smsDeliver.getSurveyId());
        } else {
            old_deliver_params.put("smtp_id", emailDeliver.getSmtpId());
            old_deliver_params.put("mail_from", emailDeliver.getMailFrom());
            old_deliver_params.put("email_subject", emailDeliver.getEmailSubject());
            old_deliver_params.put("email_template", emailDeliver.getEmailTemplate());
            old_deliver_params.put("check_submit", emailDeliver.getCheckSubmit());
            new_deliver_params.put("survey_id", emailDeliver.getSurveyId());
        }
        new_deliver_params.put("_deliver_name", deliver.getName() + "_重新投放" + recast_nums);
        new_deliver_params.put("award_id", deliver.getAwardId());
        new_deliver_params.put("award_use_type", StrUtil.isEmpty(deliver.getAwardId()) ? 0 : 1);
        new_deliver_params.put("survey_submit_type", Objects.nonNull(deliverDeliverGroup) ? 0 : 2);
        new_deliver_params.putAll(old_deliver_params);
        return new_deliver_params;
    }

    @Override
    public DeliverDeliverGroup originGetDeliverGroup(String deliverGid) {
        DeliverDeliverGroup deliverDeliverGroup = deliverDeliverGroupMapper.selectById(deliverGid);
        if (Objects.isNull(deliverDeliverGroup)) {
            throw new BusinessException(String.valueOf(ResourceErrorCodeConstants.NOT_FOUND), String.format("DeliverGroup[id=%s] not found", deliverGid));
        }
        return deliverDeliverGroup;
    }

    @Override
    public DeliverRecast getOneRecast(String deliverId) {
        LambdaQueryWrapper<DeliverRecast> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverRecast::getParentDeliver, deliverId);
        DeliverRecast deliverRecast = deliverRecastMapper.selectOne(queryWrapper);
        /*if (Objects.isNull(deliverRecast)) {
            throw new BusinessException(String.valueOf(ResourceErrorCodeEnum.NOT_FOUND.getCode()), String.format("Recast[%s] not found", "parent_deliver:" + deliverId));
        }*/
        return deliverRecast;
    }

    /**
     * 投放对黑名单或邮件退订的联系人无法重新投放
     * 先判断黑名单状态 再判断邮件订阅状态
     * 全是黑名单则提示"黑名单用户无法重新投放"
     * 全是邮件退订则提示"退订邮件用户无法重新投放"
     * 二者都有则提示"没有可重新投放的联系人"
     *
     * @param member_ids
     * @param filter_blacklist   是否过滤加入黑名单的联系人
     * @param filter_unsubscribe 是否过滤邮件退订的联系人
     */
    private List<String> filterDeliverAgainMembers(List<String> member_ids, Boolean filter_blacklist, Boolean
            filter_unsubscribe) {
        if (CollectionUtils.isEmpty(member_ids)) {
            return member_ids;
        }
        List<MemberDto> member_list = memberGrpcClient.listMembersByIds(member_ids);
        if (CollectionUtils.isEmpty(member_list)) {
            return Collections.emptyList();
        }
        List<String> filter_member_list;
        boolean has_blacklist_member;
        if (filter_blacklist) {
            //过滤加入黑名单的联系人
            filter_member_list = member_list.stream().filter(v -> !v.getMemberDeliveryStatus().equals(MemberDeliveryStatus.MEMBER_DELIVERY_STATUS_DISABLED.getValue())).map(MemberDto::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(filter_member_list)) {
                throw new BusinessException("黑名单用户无法重新投放");
            }
            has_blacklist_member = member_list.size() > filter_member_list.size();
        } else {
            filter_member_list = member_list.stream().map(MemberDto::getId).collect(Collectors.toList());
            has_blacklist_member = false;
        }
        if (filter_unsubscribe) {
            filter_member_list = member_list.stream().filter(v -> !v.getSubscribeStatus().equals(MemberSubscribeStatus.MEMBER_SUBSCRIBE_STATUS_UNSUBSCRIBE.getValue())).map(MemberDto::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(filter_member_list)) {
                if (has_blacklist_member) {
                    throw new BusinessException("没有可重新投放的联系人");
                } else {
                    throw new BusinessException("退订邮件用户无法重新投放");
                }
            }
        }
        return filter_member_list;
    }


    @Override
    public ServiceResult<?> emailDeliverUrge(String id, JSONObject param) {
        String email_deliver_id = param.getString("email_deliver_id");
        if (StrUtil.isEmpty(email_deliver_id)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "缺少邮件投放id");
        }
        String email_subject = param.getString("email_subject");
        if (StrUtil.isEmpty(email_subject)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "email_subject is requiredd");
        }
        String email_template = param.getString("email_template");
        if (StrUtil.isEmpty(email_template)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "email_template is requiredd");
        }
        String mail_from = param.getString("mail_from");
        if (StrUtil.isEmpty(mail_from)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "mail_from is requiredd");
        }
        String smtp_id = param.getString("smtp_id");
        if (StrUtil.isEmpty(smtp_id)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "smtp_id is requiredd");
        }
        DeliverEmailDeliver emailDeliver = originGetEmailDeliver(email_deliver_id);
        String orgId = SecurityContextHolder.getOrgId();
        JSONObject email_info = new JSONObject();
        email_info.put("email_subject", email_subject);
        email_info.put("email_template", email_template);
        email_info.put("mail_from", mail_from);
        email_info.put("smtp_id", smtp_id);
        List<String> member_ids;
        if (param.containsKey("member_ids")) {
            member_ids = param.getJSONArray("member_ids").toJavaList(String.class);
            if (CollectionUtils.isEmpty(member_ids)) {
                return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "缺少联系人");
            }
            member_ids = member_ids.stream().distinct().collect(Collectors.toList());
            member_ids = checkMemberDeliverStatus4Urge(member_ids, emailDeliver.getDeliverGroupId(), emailDeliver.getDeliverId(), DeliverTtypeEnum.DELIVER_TTYPE_EMAIL);
            if (!member_ids.isEmpty()) {
                member_ids = filterDeliverUrgeMembers(member_ids, false, false);
            }
            emailDeliverUrgeByMemberIds(orgId, emailDeliver, id, member_ids, email_info);
        } else {
            JSONObject filter_params = (JSONObject) param.getOrDefault("filter_params", new JSONObject());
            //催答时 已投放发送 类型的状态作为投放数据
            filter_params.put("s_type", EMAILRECORD_S_TYPE_DELIVER.getNumber());
            //免打扰拦截状态不可以催答
            String status = filter_params.getString("status");
            if (StrUtil.isEmpty(status)) {
                filter_params.put("status", Arrays.asList(EMAILRECORD_STATUS_SENDING, EMAILRECORD_STATUS_SUCCESS, EMAILRECORD_STATUS_FAILED));
            } else {
                //勾选全部催答不可选择"免打扰拦截"、"黑名单拦截"、"邮件退订"发送状态
                if (status.equals(String.valueOf(EMAILRECORD_STATUS_DISTRUB.getValue()))) {
                    return ServiceResult.fail(ReqErrorCodeConstants.PARAM_RANGE, "免打扰拦截状态不可以催答");
                }
                if (status.equals(String.valueOf(EMAILRECORD_STATUS_MEMBER_BLACKLIST.getValue()))) {
                    return ServiceResult.fail(ReqErrorCodeConstants.PARAM_RANGE, "黑名单用户无法催答");
                }
                if (status.equals(String.valueOf(EMAILRECORD_STATUS_EMAIL_UNSUBSCRIBE.getValue()))) {
                    return ServiceResult.fail(ReqErrorCodeConstants.PARAM_RANGE, "退订邮件用户无法催答");
                }
            }
            List<String> exclude_member_ids = CollectionUtils.isEmpty(param.getJSONArray("exclude_member_ids")) ? Collections.emptyList() : param.getJSONArray("exclude_member_ids").toJavaList(String.class);
            member_ids = emailDeliverRecordMembers(emailDeliver, filter_params, exclude_member_ids, id);
            if (CollectionUtils.isNotEmpty(member_ids)) {
                member_ids = filterDeliverUrgeMembers(member_ids, false, false);
            }
            emailDeliverUrgeByMemberIds(orgId, emailDeliver, id, member_ids, email_info);
        }
        Map<String, String> map = new HashMap<>(2);
        map.put("id", id);
        return ServiceResult.success(map);
    }

    /**
     * 根据传递的联系人列表进行催答
     *
     * @param orgId
     * @param emailDeliver
     * @param id
     * @param member_ids
     * @param email_info   催答重新配置的邮件相关信息
     */
    private void emailDeliverUrgeByMemberIds(String orgId, DeliverEmailDeliver emailDeliver, String
            id, List<String> member_ids, JSONObject email_info) {
        if (member_ids.size() == 1) {
            if (checkMemberDeliverUrgeStatus(member_ids.get(0), emailDeliver.getDeliverGroupId(), emailDeliver.getDeliverId())) {
                throw new BusinessException(String.valueOf(STATUS_CHANGED.getCode()), "当前用户已经提交问卷，无法催答");
            }
        }
        List<String> urge_member_ids = new ArrayList<>();
        member_ids.forEach(v -> {
            if (!checkMemberDeliverUrgeStatus(v, emailDeliver.getDeliverGroupId(), emailDeliver.getDeliverId())) {
                urge_member_ids.add(v);
            }
        });
        if (urge_member_ids.isEmpty()) {
            throw new BusinessException(String.valueOf(STATUS_CHANGED.getCode()), "没有可催答的联系人");
        }
        //进行催答
        email_info.put("member_id_list", urge_member_ids);
        email_info.put("s_type", EMAILRECORD_S_TYPE_URGE.getNumber());
        deliverEmailDeliver(emailDeliver, email_info, null, null);
    }

    /*private ServiceResult<?> asyncDeliverEmailDeliver(DeliverEmailDeliver emailDeliver, JSONObject param) {
        LambdaQueryWrapper<DeliverEmailDeliverMemberId> qwrap = new LambdaQueryWrapper<>();
        qwrap.select(DeliverEmailDeliverMemberId::getMemberId);
        qwrap.eq(DeliverEmailDeliverMemberId::getEmaildeliverId, emailDeliver.getId());
        List<DeliverEmailDeliverMemberId> objList = deliverEmailDeliverMemberIdMapper.selectList(qwrap);
        if (!org.springframework.util.CollectionUtils.isEmpty(objList)) {
            List<String> ids = objList.stream().map(DeliverEmailDeliverMemberId::getMemberId).filter(StrUtil::isNotEmpty).distinct().collect(Collectors.toList());
            emailDeliver.setMemberIdlist(ids);
        }
        String email_time = new SimpleDateFormat("yyyy年MM月dd日").format(new Date());
        Project project = qdesGrpcClient.getProject(emailDeliver.getSurveyId());
        String projectName = project.getTitle();
        String ques_name = getQdesName(emailDeliver.getSurveyId(), project.getStructId());
        String systematic_name = getSystemName(SecurityContextHolder.getOrgId());
        //如果params 中有邮件相关信息 则用params中的
        String email_template = param.getString("email_template");
        if (StringUtils.isNotEmpty(email_template)) {
            emailDeliver.setEmailTemplate(email_template);
        }
        String email_subject = param.getString("email_subject");
        if (StringUtils.isNotEmpty(email_subject)) {
            emailDeliver.setEmailSubject(email_subject);
        }
        String mail_from = param.getString("mail_from");
        if (StringUtils.isNotEmpty(mail_from)) {
            emailDeliver.setMailFrom(mail_from);
        }
        String smtp_id = param.getString("smtp_id");
        if (StringUtils.isNotEmpty(smtp_id)) {
            emailDeliver.setSmtpId(smtp_id);
        }

        Smtp userSmtp = userGrpcClient.getUserSmtpById(emailDeliver.getSmtpId());
        String mailFrom = StringUtils.isNotEmpty(userSmtp.getMailFrom()) ? userSmtp.getMailFrom() + "," + userSmtp.getAccount() : userSmtp.getAccount();

        DeliverDeliver deliver = getDeliver(emailDeliver.getDeliverId());

        HashMap<String, String> kwargs = new HashMap<>();
        if (deliver.getAwardUseType() == DELIVER_AWARD_USE_TYPE_USE.getNumber()) {
            kwargs.put("awardId", deliver.getAwardId());
        }
        Integer status = deliver.getStatus();
        if (DeliverStatusEnum.getDeliverCheck3Value().contains(status)) {
            return ServiceResult.fail(-1, "当前投放状态错误");
        }
        if (param.containsKey("member_id_list")) {
            emailDeliver.setMemberIdlist((List<String>) param.get("member_id_list"));
        }
        log.info("邮件投放的联系人的数量为:{}", emailDeliver.getMemberIdlist().size());
        if (CollectionUtils.isEmpty(emailDeliver.getMemberIdlist())) {
            log.info("邮件投放符合条件联系人的数量为0");
            return ServiceResult.fail(-1, "邮件投放符合条件联系人的数量为0");
        }
        //免打扰联系人id从投放联系人中去除
        List<String> no_disturb_member_id_list = JSONObject.parseArray(emailDeliver.getNoDisturbMemberIdList(), String.class);
        log.info("邮件投放免打扰联系人的数量为:{}", no_disturb_member_id_list.size());
        if (CollectionUtils.isNotEmpty(no_disturb_member_id_list)) {
            //取两者差集及非免打扰的联系人
            emailDeliver.setMemberIdlist((List<String>) CollectionUtils.subtract(emailDeliver.getMemberIdlist(), no_disturb_member_id_list));
        }
        LambdaQueryWrapper<DeliverEmailRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliverEmailRecord::getEmailDeliverId, emailDeliver.getId());
        queryWrapper.eq(DeliverEmailRecord::getSType, EMAILRECORD_S_TYPE_DELIVER);
        List<DeliverEmailRecord> link_list = deliverEmailRecordMapper.selectList(queryWrapper);
        Map<String, String> new_link_dict = new HashMap();
        link_list.forEach(v -> {
            String surveylink = JSONObject.parseObject(v.getParams()).getString("surveylink");
            if (StrUtil.isNotEmpty(surveylink) && ReUtil.isMatch(URL_REGEX, surveylink)) {
                new_link_dict.put(v.getMemberId(), surveylink);
            }
        });


        Integer sType = (Integer) param.get("s_type");
        //改成mq消息处理
        log.info("邮件投放发送mq消息start");

        //改成mq处理,比如5000一个mq消息，这样可以几台机器一起消费，执行投放过程
        List<List<String>> list = ListUtil.partition(emailDeliver.getMemberIdlist(), DELIVER_MQ_BATCH_SIZE);
        log.info("邮件投放{}发送{}条mq消息,每批次{}", deliver.getId(), list.size(), DELIVER_MQ_BATCH_SIZE);
        kwargs.put("deliver_g_id", emailDeliver.getDeliverGroupId());
        for (List<String> subList : list) {
            EmailDeliverMessageDto dto = new EmailDeliverMessageDto();
            dto.setId(emailDeliver.getId());
            dto.setOrgId(emailDeliver.getOrgId());
            dto.setSurveyId(emailDeliver.getSurveyId());
            dto.setDeliverId(emailDeliver.getDeliverId());
            dto.setEmailSubject(emailDeliver.getEmailSubject());
            dto.setEmailTemplateId(emailDeliver.getEmailTemplateId());
            dto.setEmailTemplate(emailDeliver.getEmailTemplate());
            dto.setCheckSubmit(emailDeliver.getCheckSubmit());
            dto.setDeliverGroupId(emailDeliver.getDeliverGroupId());
            dto.setKwargs(kwargs);
            dto.setProjectName(projectName);
            dto.setNoDisturbMemberIdlist(no_disturb_member_id_list);
            dto.setMsgTotal(list.size());
            dto.setSystemName(systematic_name);
            dto.setEmailTime(email_time);
            dto.setQuesName(ques_name);
            dto.setSType(sType);
            dto.setMemberIdlist(subList);
            dto.setEmailContacts(param.getJSONObject("email_contacts_message").toJavaObject(new TypeReference<Map<String, List<String>>>() {
            }));
            dto.setMailFrom(mailFrom);
            dto.setSmtpId(emailDeliver.getSmtpId());
            dto.setVersion(deliver.getVersion());
            dto.setNewLinkDict(new_link_dict);
            //发送mq消息
            sendDeliverMsg(dto, null);
        }
        log.info("邮件投放发送mq消息end");
        return ServiceResult.success();
    }*/

    /**
     * 检查联系人的投放状态
     *
     * @param member_ids
     * @param deliverGroupId
     * @param deliverId
     * @param deliver_type   投放类型
     * @return
     */
    @Override
    public List<String> checkMemberDeliverStatus4Urge(List<String> member_ids, String deliverGroupId, String
            deliverId, DeliverTtypeEnum deliver_type) {
        LambdaQueryWrapper<DeliverEmailRecord> queryWrapper = new LambdaQueryWrapper<>();
        //这些状态容许催答
        queryWrapper.in(DeliverEmailRecord::getStatus, SMSRecordStatus.SMSRECORD_STATUS_SENDING.getNumber(), SMSRecordStatus.SMSRECORD_STATUS_SUCCESS.getNumber(), SMSRecordStatus.SMSRECORD_STATUS_FAILED.getNumber(), SMSRecordStatus.SMSRECORD_STATUS_BALANCE_SHORT.getNumber());
        //s_type 为投放或二次投放
        queryWrapper.in(DeliverEmailRecord::getSType, SMSRecordSType.SMSRECORD_S_TYPE_DELIVER.getNumber(), SMSRecordSType.SMSRECORD_S_TYPE_AGAIN_DELIVER.getNumber());
        if (member_ids.size() == 1) {
            queryWrapper.eq(DeliverEmailRecord::getMemberId, member_ids.get(0));
            queryWrapper.eq(DeliverEmailRecord::getDeliverId, deliverId);
            if (StrUtil.isNotEmpty(deliverGroupId)) {
                queryWrapper.eq(DeliverEmailRecord::getDeliverGroupId, deliverGroupId);
            }
            DeliverEmailRecord record = deliverEmailRecordMapper.selectOne(queryWrapper);
            return Objects.nonNull(record) ? member_ids : Collections.emptyList();
        }
        //先查出对应的所有可以催答的投放member_ids，之后取交集
        queryWrapper.eq(DeliverEmailRecord::getDeliverId, deliverId);
        if (StrUtil.isNotEmpty(deliverGroupId)) {
            queryWrapper.eq(DeliverEmailRecord::getDeliverGroupId, deliverGroupId);
        }
        List<String> db_member_id_set = deliverEmailRecordMapper.selectList(queryWrapper).stream().map(DeliverEmailRecord::getMemberId).distinct().collect(Collectors.toList());
        return (List<String>) CollectionUtils.intersection(db_member_id_set, member_ids);
    }

    @Override
    public ServiceResult<?> emailDelivers(EmailDeliversParam param) {
        String deliverName = param.getDeliverName();
        if (StringUtils.isEmpty(deliverName)) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "投放名称参数缺失");
        }
        if (deliverName.length() > 30) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_RANGE, "投放名称超出长度限制");
        }
        OrgInfoDto organization = userGrpcClient.getOrganization(SecurityContextHolder.getOrgId());
        boolean isCheck = Optional.ofNullable(organization.getIsDeliverCheck()).orElse(false);
        if (isCheck != (param.getIsCheck() == 1)) {
            return ServiceResult.fail(ValidationErrorCodeEnum.ORG_DELIVER_CHECK_CHANGED.getCode(), ValidationErrorCodeEnum.ORG_DELIVER_CHECK_CHANGED.getMsg());
        }
        String deliverId = createEmailDeliver(param);
        if (Objects.nonNull(param.getIsDelay()) && param.getIsDelay() == 1 && Objects.isNull(param.getDeliverTime())) {
            return ServiceResult.fail(ReqErrorCodeConstants.PARAM_LOST, "投放定时时间参数缺失");
        }
        if (isCheck) {
            //保存之后投放状态改为 “未投放”
            deliverService.updateDeliver(deliverId);
        }
        Map<String, String> res = new HashMap<>(2);
        res.put("id", deliverId);
        return ServiceResult.success(res);
    }

    @Override
    public String createEmailDeliver(EmailDeliversParam param) {
        String orgId = SecurityContextHolder.getOrgId();
        Integer surveySubmitType = Optional.ofNullable(param.getSurveySubmitType()).orElse(SurverySubmitTyeEnum.LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex());
        if (surveySubmitType.equals(SurverySubmitTyeEnum.LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex())) {
            originGetDeliverGroup(param.getDeliverGid());
        }
        DeliverDeliver deliver;
        if (param instanceof EmailDeliversParamAgain) {
            EmailDeliversParamAgain again = (EmailDeliversParamAgain) param;
            deliver = createDeliver(orgId, param.getDeliverId(), param.getDeliverName(), param.getDeliverTime(), DELIVER_TTYPE_EMAIL.getValue(),
                    DeliverChannel.DELIVER_CHANNEL_EMAIL.getNumber(), again.getAwardUseType(), again.getAwardId());
        } else {
            deliver = createDeliver(orgId, param.getDeliverId(), param.getDeliverName(), param.getDeliverTime(), DELIVER_TTYPE_EMAIL.getValue(),
                    DeliverChannel.DELIVER_CHANNEL_EMAIL.getNumber(), DELIVER_AWARD_USE_TYPE_UNUSE.getNumber(), null);
        }
        String deliverId = deliver.getId();
        param.setDeliverId(deliverId);
        deliverService.setDeliverRespondentEnableRedis(deliverId, true);

        deliverCreateSurveydeliver(orgId, param.getSurveyId(), deliverId);
        if (SurverySubmitTyeEnum.LIMITED_ONE_SURVERY_SUBMINT_TYPE.getIndex().equals(surveySubmitType)) {
            String deliverGroupId = createDeliverGroup(orgId, param.getSurveyId(), Collections.singletonList(deliver.getId()));
            log.info("创建投放组成功：dliver_g_id={}", deliverGroupId);
            param.setDeliverGid(deliverGroupId);
        } else if (SurverySubmitTyeEnum.LIMITED_ONE_IN_DELIVER_GROUP_SUBMINT_TYPE.getIndex().equals(surveySubmitType)) {
            addDeliverToGroup(deliverId, param.getSurveyId(), param.getDeliverGid());
        }

        Map<String, Object> signMap = new HashMap<>(4);
        signMap.put("email_subject", Optional.ofNullable(param.getEmailSubject()).orElse(""));
        signMap.put("email_template", Optional.ofNullable(param.getEmailTemplate()).orElse(""));
        String hashcode = SignUtil.genSign(signMap, deliverService.getDeliverSecret());
        originCreateEmailDeliver(orgId, param, hashcode);
        deliverService.doDefaultDeliverNameSeq(param.getDeliverName(), param.getSurveyId(), DELIVER_TTYPE_EMAIL.getValue());
        return deliverId;
    }

    @Override
    public DeliverDeliver createDeliver(String orgId, String deliverId, String deliverName, LocalDateTime
            deliverTime, Integer ttype, Integer channel, int awardUseType, String awardId) {
        DeliverDeliver deliver = new DeliverDeliver();
        deliver.setName(deliverName);
        deliver.setOrgId(orgId);
        deliver.setCreatedId(SecurityContextHolder.getUserId());
        deliver.setTtype(ttype);
        deliver.setChannel(channel);
        deliver.setScenes(DeliverScenes.DELIVER_SCENES_TIMING.getNumber());
        deliver.setStatus(DeliverStatus.DELIVER_STATUS_STOP.getNumber());
        deliver.setStarttime(LocalDateTime.now());
        deliver.setDeliverTime(deliverTime);
        deliver.setAwardUseType(awardUseType);
        deliver.setAwardId(awardId);
        // 获取当前时间戳，单位微秒
        deliver.setVersion(System.currentTimeMillis() * 1000);
        deliver.setId(StringUtils.isNotEmpty(deliverId) ? deliverId : new ObjectId().toHexString());
        deliver.setCode(String.valueOf(serviceSequenceService.getSequence("deliver_id", 1)));
        // 设置默认值
        deliver.setDisable(0);
        deliver.setDelayTime("[]");
        deliver.setDelayFailedTime("{}");
        deliver.setEnableRespondent(1);
        deliverDeliverMapper.insert(deliver);
        return deliver;
    }

    @Override
    public void deliverCreateSurveydeliver(String orgId, String surveyId, String deliverId) {
        DeliverSurveyDeliver deliverSurveyDeliver = new DeliverSurveyDeliver();
        deliverSurveyDeliver.setOrgId(orgId);
        deliverSurveyDeliver.setSurveyId(surveyId);
        deliverSurveyDeliver.setDeliverId(deliverId);
        deliverSurveyDeliverMapper.insert(deliverSurveyDeliver);
    }

    /**
     * 创建投放组
     *
     * @param orgId
     * @param surveyId
     * @param deliverList
     * @return
     */
    @Override
    public String createDeliverGroup(String orgId, String surveyId, List<String> deliverList) {
        DeliverDeliverGroup deliverDeliverGroup = new DeliverDeliverGroup();
        deliverDeliverGroup.setOrgId(orgId);
        deliverDeliverGroup.setSurveyId(surveyId);
        deliverDeliverGroupMapper.insert(deliverDeliverGroup);
        String deliverGroupId = deliverDeliverGroup.getId();
        deliverList.forEach(v -> {
            DeliverDeliverGroupDeliver groupDeliver = new DeliverDeliverGroupDeliver();
            groupDeliver.setDeliverGroupId(deliverGroupId);
            groupDeliver.setDeliverId(v);
            deliverDeliverGroupDeliverMapper.insert(groupDeliver);
        });
        return deliverGroupId;
    }

    private void originUpdateDeliverGroup(DeliverGroupVo deliverGroupVo, String surveyId) {
        String orgId = SecurityContextHolder.getOrgId();
        //如果参数中有member_id_list就先把原先数据删除
        if (CollUtil.isNotEmpty(deliverGroupVo.getDeliverList())) {
            List<DeliverDeliverGroupDeliver> deliverList = deliverGroupVo.getDeliverList();
            if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isNotEmpty(deliverList)) {
                LambdaQueryWrapper<DeliverDeliverGroupDeliver> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(DeliverDeliverGroupDeliver::getDeliverGroupId, deliverGroupVo.getId());
                deliverDeliverGroupDeliverMapper.delete(queryWrapper);
                createDeliverGroupDeliver(deliverList, deliverGroupVo.getId());
            }
            updateDeliverGroup(orgId, surveyId, deliverGroupVo.getId());
        }
    }

    private void createDeliverGroupDeliver(List<DeliverDeliverGroupDeliver> deliverList, String groupId) {
        deliverList.forEach(v -> {
            DeliverDeliverGroupDeliver deliver = new DeliverDeliverGroupDeliver();
            deliver.setId(new ObjectId().toHexString());
            deliver.setDeliverId(v.getDeliverId());
            deliver.setDeliverGroupId(groupId);
            deliverDeliverGroupDeliverMapper.insert(deliver);
        });
    }

    private void updateDeliverGroup(String orgId, String surveyId, String id) {
        DeliverDeliverGroup group = new DeliverDeliverGroup();
        group.setOrgId(orgId);
        group.setSurveyId(surveyId);
        group.setId(id);
        deliverDeliverGroupMapper.updateById(group);
    }


    private void originCreateEmailDeliver(String orgId, EmailDeliversParam param, String hashcode) {
        DeliverEmailDeliver emailDeliver = new DeliverEmailDeliver();
        emailDeliver.setOrgId(orgId);
        emailDeliver.setSurveyId(param.getSurveyId());
        emailDeliver.setDeliverId(param.getDeliverId());
        emailDeliver.setDeliverGroupId(param.getDeliverGid());
        emailDeliver.setCheckSubmit(param.getCheckSubmit());
        emailDeliver.setHashcode(hashcode);
        emailDeliver.setIsDelay(Optional.ofNullable(param.getIsDelay()).orElse(0));
        emailDeliver.setIsCheck(Optional.ofNullable(param.getIsCheck()).orElse(0));
        emailDeliver.setDeliverTime(param.getDeliverTime());
        emailDeliver.setAntiDisturTimes(Optional.ofNullable(param.getAntiDisturTimes()).map(JSON::toJSONString).orElse("[]"));
        if (param instanceof EmailDeliversParamAgain) {
            EmailDeliversParamAgain again = (EmailDeliversParamAgain) param;
            emailDeliver.setSmtpId(again.getSmtpId());
            emailDeliver.setMailFrom(again.getMailFrom());
            emailDeliver.setEmailSubject(again.getEmailSubject());
            emailDeliver.setEmailTemplate(again.getEmailTemplate());
        }
        emailDeliver.setOptionDeliverTime("{}");
        emailDeliver.setFilterParams("{}");
        emailDeliver.setNoDisturbMemberIdList("[]");
        log.info("新增邮件投放参数{}", emailDeliver);
        baseMapper.insert(emailDeliver);

        String emailDeliverId = emailDeliver.getId();
        List<String> memberIds = param.getMemberIdlist();
        batchInsertEmailDeliverMemberId(emailDeliverId, memberIds);
    }
}